[英]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 ++中是否有new
和delete
包含相同的東西。 我在原始循環中為Customer
分配了內存,但是我嘗試使用另一個類的方法返回內存。 這是管理內存的有效方法,還是有更好的方法來執行此操作?
C ++中的規則略有不同:您的程序需要調用delete
或delete[]
運算符,具體取決於您用來分配內存的運算符。
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::list
或std::vector
。 當Customer
從列表中刪除時(包括整個列表被銷毀時),這將自動刪除Customer
。
順便說一句, remove
lead->setNext(NULL)
是不必要的。 您正在更改將要刪除的對象中的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.