Using the destructor to free linked objects

2019-09-01 18:59发布

问题:

I have a class called "node". I link a bunch of node objects together to form a linked list. When the "node" destructor is called, it only deletes the first node. How do I iterate through the entire linked list of nodes and delete each node object?

Here is the class definition:

class Node
{
private:
double coeff;
int exponent;
Node *next;
public:

Node(double c, int e, Node *nodeobjectPtr)
{
    coeff = c;
    exponent = e;
    next = nodeobjectPtr;
}

~Node()
{
    printf("Node Destroyed");
}

The destructor is called by invoking delete on the pointer to the first node of the linked node list.

回答1:

Since you don't know how many nodes there are in a list, if you do not have firm bounds on that it's not a good idea to invoke destructors recursively, because each call uses some stack space, and when available stack space is exhausted you get Undefined Behavior, like a crash.

So if you absolutely want to do deallocate following nodes in a node's destructor, then it has to first unlink each node before destroying it.

It can go like this:

Node* unlink( Node*& p )
{
    Node* result = p;
    p = p->next;
    result->next = nullptr;
    return result;
}

Node::~Node()
{
    while( next != nullptr )
    {
        delete unlink( next );
    }
}

But better, make a List object that has ownership of the nodes in a linked list.

Of course, unless this is for learning purposes or there is a really good reason to roll your own linked list, just use a std::vector (and yes I mean that, not std::list).



回答2:

How do I iterate through the entire linked list of nodes and delete each node object?

It would be cleaner if you had a separate class to manage the entire list, so that nodes can be simple data structures. Then you just need a simple loop in the list's destructor:

while (head) {
    Node * victim = head;
    head = victim->next;    // Careful: read this before deleting
    delete victim;
}

If you really want to delegate list management to the nodes themselves, you'll need to be a bit more careful:

while (next) {
    Node * victim = next;
    next = victim->next;
    victim->next = nullptr;  // Careful: avoid recursion
    delete victim;
}

Under this scheme, you'll also need to be careful when deleting a node after removing it from the list - again, make sure you reset its pointer so it doesn't delete the rest of the list. That's another reason to favour a separate "list" class.