Как освободить память, указанную статическим указателем в классе C ++ - PullRequest
0 голосов
/ 10 октября 2018
#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;

В классе Link есть статический указатель, предназначенный для сохранения списка freelist в моем связанном списке, и я хочу освободить память этого freelist после завершения программы.Как я могу удалить память этого freelist.

PS: я пытался освободить память следующим образом:

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

Но программа прекратилась без причины.

1 Ответ

0 голосов
/ 10 октября 2018

Но программа прекратилась без причины.

Давайте посмотрим на этот цикл.Здесь вы удаляете элемент:

delete freelist;

И затем, после удаления, вы получаете доступ к нему в условии цикла:

while (freelist->next != nullptr)

Это неопределенное поведение.Вы получаете доступ к элементу, который вы удалили.Я бы предложил вместо этого сделать рекурсию, просмотреть список и удалить элементы на выходе.Возможно, что-то вроде

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

А затем позвоните на freelist.Кроме того, вам нужно удалить следующую перегрузку:

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

Так что, если я правильно понимаю, когда вы удаляете Link, вы устанавливаете next ссылки (которая собирается быть удаленаво всяком случае, так что ничего не делает), а затем вы установите freelist для этой ссылки, которая теперь станет недействительной.Это приведет к удалению элементов.

Как указал Кристоф, удаление такого большого списка может привести к переполнению стека.Этого можно избежать, используя алгоритм, который не использует рекурсию.Вы можете попробовать что-то вроде этого:

/** 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;
    }
}
...