Использование shared_ptr для связанного списка дает стекопоток внутри деструктора - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь реализовать связанный список, используя shared_ptr, а не сырые указатели.Код:

#include <memory>
class NodeTest
{
private:
    int v;
    std::shared_ptr<NodeTest> next;
public:
    NodeTest() { v = 0; };
    NodeTest(unsigned int i) { v = i; }
    ~NodeTest() {};
    void setNext(std::shared_ptr<NodeTest> & toSet) { next = toSet; }
};

std::shared_ptr<NodeTest> init()
{
    std::shared_ptr<NodeTest> elt = std::shared_ptr<NodeTest>(new NodeTest());
    std::shared_ptr<NodeTest> first = elt;
    for (unsigned int i = 1; i < 5000; i++)
    {
        std::shared_ptr<NodeTest> next(new NodeTest(i));
        elt->setNext(next);
        elt = next;
    }
    return first;
}

void test_destroy()
{
    std::shared_ptr<NodeTest> aList = init();
}


int main(int argc, char * argv[])
{
    test_destroy();
}

Это генерирует переполнение стека при выходе из области действия test_destroy() из-за вызова деструктора aList (RAII).Чтобы уничтожить aList, он вызывает деструктор next и т. Д., Который, очевидно, заканчивается потоком стека для достаточно большого списка.

Я не могу найти какой-либо эффективный способ исправить это.Идеальным вариантом было бы удалить текущую NodeTest перед тем, как перейти к удалению next, верно?Как бы вы поступили так?

Заранее спасибо

Решение: Вам необходимо разорвать связи между всеми узлами И сохранить указатель на каждый узел так, чтобыДеструктор не сразу вызывается при разрыве ссылок.Пример ниже с использованием вектора.

~NodeTest() 
{
    std::vector<std::shared_ptr<NodeTest>> buffer;
    std::shared_ptr<NodeTest> cursor = next;

    while (cursor.use_count()!=0)
    {
        std::shared_ptr<NodeTest> temp = cursor->getNext();
        cursor->setNext(std::shared_ptr<NodeTest>());
        buffer.push_back(cursor);
        cursor = temp;
    }

    next = std::shared_ptr<NodeTest>();
};

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

В этом случае вы должны управлять удалением узлов вручную, потому что деструктор вызывает деструктор, вызывает деструктор .....

Взгляните на доклад CppCon 2016: Herb Sutter «Leak-Freedom в C ++... По умолчанию. ”

0 голосов
/ 21 февраля 2019

Деструктор NodeTest вызывает деструктор NodeTest::next, который рекурсивно вызывает другой деструктор NodeTest и так далее, пока стек не будет исчерпан.По этой причине интеллектуальные указатели не должны использоваться для связывания узлов.

...