I'm building a program that will process some fake book orders, and I think I've run into a problem with how I am allocating my memory.
The program flow starts by opening up a text file with the information about each customer. I tokenize that information in a loop and create Customer
objects that I want to insert into a database. Here is the loop I am using:
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);
}
I use the database
as a way to store the Customer
objects, which get modified later on in the program. The point is that these Customer
objects will be modified and will stick around in the database indefinitely until the end of the program. The problem arises when I try to clean up the memory allocated for these Customers
. My database
is set up as a sorted linked list, and this is the function I use to remove Customers
from the database
:
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;
}
My concern is that I am not deleting the Customer
objects correctly. I know that in C the exact pointer created by malloc
needs to be given back to free
, but I'm not sure if the same thing holds in C++ with new
and delete
. I allocated memory for the Customer
in the original loop, but I try to return the memory using a method of another class. Is this a valid way to manage the memory, or is there a better way to do this?
The rules in C++ are a little different: your program needs to make a call of either delete
or delete[]
operator, depending on the operator that you used to allocate the memory.
new
to allocate memory for a single object, use delete
operator new[]
to allocate memory for an array of objects, use delete[]
operator In your case you need to call delete
(with no square brackets) on the instance of Customer
. This should work fine, because all Customer
objects are allocated in a loop and added to a non-shared container. Essentially, your linked list "owns" all your Customer
objects. In cases like this, removing of a object from the list should trigger deallocation. In situations when your objects could be used from other places (ie the pointers are shared) removing an item from the list should not de-allocate the object.
Note: this is a very low-level of doing things. C++ library provides ready-made list containers, along with smart pointers that you could use for unique and for shared objects, which greatly simplifies the code.
阅读有关RAII的信息 -资源获取是初始化,并使用智能指针来促进资源管理(尤其是分配的内存)
You're correct about using delete
to free up memory allocated with new
. I'm assuming that database
is of type CusttomerList
. In that case your code should work fine as long as you didn't accidentally delete
or change any pointers in the list earlier. This is exactly why you should only use "naked new
" when you absolutely have to. Instead, you can try `std::unique_ptr' in this case:
while(fgets(stringBuf,100,dbFile))
{
// ...
std::unique_ptr<Customer> newEntry
{ new Customer(name,custID,credit,street,state,zip)};
database.insert(std::move(newEntry));
}
Of course you have to declare your list to be list<unique_ptr<Customer>>
(assuming that you use the STL linked list. Then whenever you want to delete an element you call `element.reset()' and the memory is released automatically. One other advantage of this method is that you don't actually have to free up memory at all, since all unique pointers will automatically release the allocated memory whenever they go out of scope (eg by the end of the program). You should read more about smart pointers, because in most cases they make resource management more, well, manageable.
You might also want to put the following line in your main()
to detect memory leaks:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
Your remove
function appears to be correctly deleting the Customer
objects, if that's what you're asking about. It doesn't correctly handle the case where the list is empty (ie this->getHead()
returns null
), though — it should check lead
before trying to dereference it in the loop.
You're making things unnecessarily difficult for yourself by managing this linked list manually, however. It'd be much simpler to store the newly-allocated Customer
pointer in a std::unique_ptr
(assuming you're using C++11) and then store that in a std::list
or std::vector
. This will take care of automatically deleting the Customer
when it's removed from the list (including when the entire list is destroyed).
BTW, the lead->setNext(NULL)
in remove
is unnecessary. You're changing values in an object that's about to be deleted anyway.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.