我正在构建一个程序来处理一些假书订单,我想我在如何分配内存方面遇到了问题。
程序流首先打开一个包含每个客户信息的文本文件。我在循环中标记该信息,并创建要插入到数据库中的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 listn";
return;
}
else {
tail->setNext(lead->getNext());
lead->setNext(NULL);
delete lead;
return;
}
我担心的是我没有正确删除Customer
对象。我知道在 C 中,malloc
创建的确切指针需要返回给free
,但我不确定同样的事情是否适用于 new
和 delete
C++。我在原始循环中为Customer
分配了内存,但我尝试使用另一个类的方法返回内存。这是管理内存的有效方法,还是有更好的方法?
> C++中的规则略有不同:程序需要调用delete
运算符或delete[]
运算符,具体取决于用于分配内存的运算符。
- 如果使用
new
为单个对象分配内存,请使用delete
运算符 - 如果使用
new[]
为对象数组分配内存,请使用delete[]
运算符
在您的情况下,您需要在 Customer
的实例上调用 delete
(不带方括号(。这应该可以正常工作,因为所有Customer
对象都在循环中分配并添加到非共享容器中。本质上,您的链表"拥有"您所有Customer
对象。在这种情况下,从列表中删除对象应该会触发释放。在可以从其他地方使用对象的情况下(即指针是共享的(,从列表中删除项目不应取消分配该对象。
注意:这是一个非常低层次的做事。C++库提供了现成的列表容器,以及可用于唯一对象和共享对象的智能指针,从而大大简化了代码。
您的remove
函数似乎正确删除了Customer
对象,如果这是您要询问的。 它不能正确处理列表为空的情况(即 this->getHead()
返回 null
(,但是 — 它应该在尝试在循环中取消引用它之前检查lead
。
但是,通过手动管理此链表,您会给自己带来不必要的困难。 将新分配的Customer
指针存储在std::unique_ptr
中会简单得多(假设您使用的是 C++11(,然后将其存储在std::list
或std::vector
中。 这将负责在从列表中删除Customer
时(包括销毁整个列表时(自动删除该。
顺便说一句,remove
lead->setNext(NULL)
是不必要的。 您正在更改无论如何都要删除的对象中的值。
RAII 的信息 - 资源获取是初始化并使用智能指针 它们有助于资源管理(尤其是分配的内存(
您使用delete
释放分配的内存是正确的 new
.我假设database
属于 CusttomerList
型。在这种情况下,只要您之前没有意外delete
或更改列表中的任何指针,您的代码就可以正常工作。这就是为什么你应该只在绝对必要的时候使用"裸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 );