I'm writing a linked list and I want a struct's destructor (a Node struct) to simply delete itself, and not have any side effects. I want my list's destructor to iteratively call the Node destructor on itself (storing the next node temporarily), like this:
//my list class has first and last pointers
//and my nodes each have a pointer to the previous and next
//node
DoublyLinkedList::~DoublyLinkedList
{
Node *temp = first();
while (temp->next() != NULL)
{
delete temp;
temp = temp->next();
}
}
So this would be my Node destructor:
Node::~Node
{
delete this;
}
Is this acceptable, especially in this context?
Both should never be done.
This
will cause undefined behaviour - you're not allowed to access memory that you've returned to the heap. Instead it shoud be:
Calling
delete this
will lead to so-called double free which will also cause undefined behaviour. The destructor should only call delete for pointer member variables, never forthis
. Callingdelete this
is reasonable from other methods to deallocate the current object, but not from the destructor.delete this; would call the destructor of the current object. In that case, if you are calling delete this; in the destructor, then the destructor would be called infinitely till the crash.
No you should not
delete this
from the destructor. The destructor gets called because of a delete statement (or goes out of scope) and this would most likely lead to some sort of crash.You also have a couple problems in the DoublyLinkedList desturctor. One, you delete temp then access temp after its been deleted. Second, the code will not actually delete the last element in the linked list.
Before anything else: I really, really hope this is homework assigned to you in order to understand a doubly linked list. Otherwise there is no reason to use this instead of
std::list
. With this out of the way:No,
delete this
in a dtor is always wrong, as the dtor is called whenthis
is in the state of being deleted.Also, while
incidentally might work, it's certainly wrong, since, where you attempt to access
temp->next()
,temp
is already deleted, so you should call a member function on it. Doing so invokes so-called "undefined behavior". (In short: It might do what you want, but it might just as well fail always or sporadically or only when Friday, 13th, collides with new moon. It migh also invoke very nasty nasal demons on you.)Note that you could solve both problems by deleting the next node in your node's dtor:
That way, your list dtor becomes very easy, too:
To me, this seems what dtors were invented for, so, except for the fact that nobody should write their own linked list types anymore nowadays, to me this seem to be the C++ solution to your problem.
Currently, your code would cause an access violation, since the second of the following lines clearly accesses freed memory:
If you want to recursively delete the structure, you want something like this:
In general, a destructor should just worry about delete-ing (or free-ing if you're using C or malloc) any memory allocated specifically for your object. Deleting a pointer to your object will always be managed by the OS and you don't have to worry about a thing about that part.
One thing worth keeping in mind is that, on construction, you create the object first (as control flow enters the constructor's body), THEN the objects inside; for destruction, you have to do that in reverse, because if you delete the outer object first you would have no way to access the inner pointers to delete those. Instead, you delete inner objects using the destructor, then the OS manages the actual freeing up of memory when control flow falls out of the destructor.
Incidentally, the same sort of thing happens with subclassing-- if you have class A, and class B : public A, then when you do a new B(), the A constructor executes first, then the B's constructor; on destruction, the B's destructor executes first, followed by A's. I'm fairly sure that you do NOT have to worry about this, though-- C++ takes care of it for you. So don't try to figure out a way to call delete on the superclass.