簡體   English   中英

如何正確管理動態分配對象的內存?

[英]How do I correctly manage the memory of dynamically allocated objects?

我正在構建一個程序,該程序將處理一些假書訂單,我認為我在分配內存方面遇到了問題。

程序流程首先打開一個文本文件,其中包含有關每個客戶的信息。 我將這些信息標記為一個循環,並創建要插入數據庫的Customer對象。 這是我正在使用的循環:

    while(fgets(stringBuf,100,dbFile))
    {

            string name(strtok(stringBuf,"|"));
            int custID = atoi(strtok(NULL,"|"));
            double credit = atof(strtok(NULL,"|"));
            string street(strtok(NULL,"|"));
            string state(strtok(NULL,"|"));
            string zip(strtok(NULL,"|"));


            Customer *newEntry = new Customer(name,custID,credit,street,state,zip);

            database.insert(newEntry);
    }

我將database用作存儲“ Customer對象的一種方式,稍后將在程序中對其進行修改。 關鍵是這些Customer對象將被修改,並將無限期地停留在數據庫中,直到程序結束。 當我嘗試清理為這些Customers分配的內存時,就會出現問題。 我的database設置為排序的鏈表,這是我用來從database刪除“ Customers的功能:

 void CustomerList::remove(int ID)
 {
    Customer *lead = this->getHead();
    Customer *tail = NULL;

    while(lead->getID() != ID) {
            tail = lead;
            lead = lead->getNext();
    }

    if(tail == NULL) { // means that lead is pointing to head
            this->setHead(lead->getNext());
            lead->setNext(NULL);
            delete lead;
            return;
    }
    else if(lead == NULL) { // element not found in the list        
            cout << "Element to be removed was not found in the list\n";
            return;
    }
    else {
            tail->setNext(lead->getNext());
            lead->setNext(NULL);
            delete lead;
            return;
 }

我擔心的是,我沒有正確刪除Customer對象。 我知道在C語言中,由malloc創建的確切指針需要返回給free ,但是我不確定C ++中是否有newdelete包含相同的東西。 我在原始循環中為Customer分配了內存,但是我嘗試使用另一個類的方法返回內存。 這是管理內存的有效方法,還是有更好的方法來執行此操作?

C ++中的規則略有不同:您的程序需要調用deletedelete[]運算符,具體取決於您用來分配內存的運算符。

  • 如果您使用new為單個對象分配內存,請使用delete運算符
  • 如果使用new[]為對象數組分配內存,請使用delete[]運算符

在您的情況下,您需要在Customer實例上調用delete (不帶方括號)。 這應該可以正常工作,因為所有Customer對象都在一個循環中分配並添加到非共享容器中。 本質上,您的鏈接列表“擁有”所有“ Customer對象。 在這種情況下,從列表中刪除對象將觸發釋放。 在可以從其他地方使用您的對象(即共享指針)的情況下,從列表中刪除某項不應取消分配該對象。

注意:這是一個非常低級的服務器。 C ++庫提供了現成的列表容器,以及可用於唯一對象和共享對象的智能指針,從而大大簡化了代碼。

閱讀有關RAII的信息 -資源獲取是初始化,並使用智能指針來促進資源管理(尤其是分配的內存)

關於使用delete釋放分配給new內存,您是正確的。 我假設database的類型為CusttomerList 在這種情況下,只要您沒有意外delete或更改列表中的任何指針,您的代碼就可以正常工作。 這就是為什么您絕對必須只使用“ naked new ”的原因。 相反,在這種情況下,您可以嘗試`std :: unique_ptr':

while(fgets(stringBuf,100,dbFile))
{

        // ...

        std::unique_ptr<Customer> newEntry
        { new Customer(name,custID,credit,street,state,zip)};

        database.insert(std::move(newEntry));
}

當然,您必須聲明列表為list<unique_ptr<Customer>> (假設您使用的是STL鏈接列表。然后,每當要刪除元素時,都調用`element.reset()“,內存會自動釋放該方法的另一個優點是,您實際上根本不需要釋放內存,因為所有唯一指針只要在超出范圍(例如,在程序末尾)時就會自動釋放分配的內存。了解更多有關智能指針的信息,因為在大多數情況下,它們使資源管理更加完善,易於管理。

您可能還希望將以下行放入main()以檢測內存泄漏:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

如果您要的是,則您的remove功能似乎正在正確刪除Customer對象。 但是,它不能正確處理列表為空的情況(即this->getHead()返回null )—它應在嘗試在循環中取消引用前檢查lead

但是,通過手動管理此鏈接列表,使您不必要地感到困難。 將新分配的Customer指針存儲在std::unique_ptr (假設您使用的是C ++ 11)要簡單得多,然后將其存儲在std::liststd::vector Customer從列表中刪除時(包括整個列表被銷毀時),這將自動刪除Customer

順便說一句, remove lead->setNext(NULL)是不必要的。 您正在更改將要刪除的對象中的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM