对linked_list使用shared_ptr可在析构函数中提供stackoverflow

问题描述 投票:1回答:2

我正在尝试使用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()析构函数(RAII)而在离开aList范围时生成stackoverflow。要销毁aList,它会调用next的析构函数等等,这显然最终得到了一个足够大的列表的stackoverflow。

我找不到任何有效的方法来解决这个问题。理想的情况是在移动到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>();
};
c++ linked-list stack-overflow shared-ptr
2个回答
1
投票

在这种情况下,您应该管理节点手动删除,因为析构函数调用析构函数调用析构函数.....

看看谈话CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”


0
投票

NodeTest的析构函数调用NodeTest::next的析构函数,递归调用另一个NodeTest析构函数,依此类推,直到堆栈耗尽为止。出于这个原因,智能指针不应该用于链接节点。

© www.soinside.com 2019 - 2024. All rights reserved.