Chengkun Li
Chengkun Li

Reputation: 133

How to release the memory pointed by a static pointer in a C++ class

#pragma once // Link.h

#include <memory>
template <typename E>
class Link
{
private:
    static Link<E> * freelist; // Pointer to the freelist head
                              // How to release the memory??

public:
    E element;
    Link *next;

    Link(const E &eleval, Link *nextval = nullptr)
        : element(eleval)
        , next(nextval) {}
    Link(Link *nextval = nullptr) : next(nextval) {}

    /*~Link()
    {
        while (freelist->next != nullptr)
        {
            Link<E> *tmp = freelist;
            freelist = freelist->next;
            delete tmp;
        }
    }
*/
    void *operator new(size_t)
    {
        if (freelist == nullptr) return ::new Link;
        Link<E>* temp = freelist;
        freelist = freelist->next;
        return temp;
    }

    void operator delete(void* ptr)
    {
        ((Link<E>*)ptr)->next = freelist;
        freelist = (Link<E>*)ptr;
    }
};

template <typename E>
Link<E>* Link<E>::freelist = nullptr;

There is a static pointer in the class Link aimed to store the freelist in my linked list, and I want to free the memory of this freelist after the program end. How can I delete the memory of this freelist.

PS: I tried to free the memory like this:

/*~Link()
    {
        while (freelist->next != nullptr)
        {
            Link<E> *tmp = freelist;
            freelist = freelist->next;
            delete tmp;
        }
    }
*/

But the program terminated for no reason.

Upvotes: 2

Views: 623

Answers (1)

Blaze
Blaze

Reputation: 16876

But the program terminated for no reason.

Let's have a look at that loop. Here you delete the item:

delete freelist;

And then, after you deleted it, you access it in the loop condition:

while (freelist->next != nullptr)

That's undefined behavior. You're accessing an element that you deleted. I would suggest instead doing recursion, traversing the list and deleting the elements on the way out. Perhaps something like

/** Delete a link and all the ones after it as well */
void recursiveDelete()
{
    if (next){
        next->recursiveDelete();
    }
    delete this;
}

And then call that on freelist. Also, you need to remove the following overload:

void operator delete(void* ptr)
    {
        ((Link<E>*)ptr)->next = freelist;
        freelist = (Link<E>*)ptr;
    }

So if I understand this right, when you delete a Link, you set the next of the link (which is about to be deleted anyway, so that does nothing) and then you set freelist to that link that will now become invalid. This will mess with deleting the items.

As Christophe pointed out, deleting an large list like that might lead to a stack overflow. It's possible to avoid that by using an algorithm that doesn't use recursion. You could try something like this:

/** Delete a link and all the ones after it as well */
void deleteAll()
{
    std::vector<Link*> links;
    Link* toDelete = this;
    while (toDelete) {
        links.push_back(toDelete);
        toDelete = toDelete->next;
    }
    for (Link* i : links) {
        delete i;
    }
}

Upvotes: 1

Related Questions