使用 shared_ptr 进行linked_list会在析构函数中产生堆栈溢出
Using shared_ptr for linked_list gives stackoverflow within destructor
我正在尝试使用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
。为了销毁aList
,它调用了next
等的析构函数,这显然最终会得到足够大的列表的堆栈溢出。
我找不到任何有效的方法来解决这个问题。理想的情况是在移动到next
删除之前删除当前NodeTest
,对吗?你会怎么做这样的事情?
提前致谢
解决方案:您需要断开所有节点之间的链接并保存指向每个节点的指针,以便在断开链接时不会立即调用析构函数。下面使用向量的示例。
~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>();
};
在这种情况下,您应该手动管理节点删除,因为析构函数调用析构函数调用析构函数.....
看看演讲 CppCon 2016:赫伯·萨特"C++中的泄漏自由......默认情况下。
NodeTest
的析构函数调用NodeTest::next
的析构函数,后者递归调用另一个NodeTest
析构函数,依此类推,直到堆栈耗尽。因此,不应使用智能指针来链接节点。
相关文章:
- C++析构函数调用两次,堆栈分配的复合对象
- 为什么析构函数无休止地调用自己(导致堆栈溢出)?
- 堆栈展开如何与析构函数调用有关?
- 受保护的析构函数禁用在堆栈上创建派生类的对象?
- 返回堆栈变量时停止调用析构函数
- 使用 shared_ptr 进行linked_list会在析构函数中产生堆栈溢出
- 堆栈调用析构函数,即使遵循三规则
- 用于堆栈分配对象的C++虚拟析构函数内联
- 是否可以在容器之类的堆栈中创建非递归析构函数
- 堆栈上的对象被覆盖时未调用析构函数
- 堆栈异常处理和析构函数展开.如何使用这些信息
- 析构函数上的 =delete 如何阻止堆栈分配
- 析构函数在(堆栈)变量之间的赋值时调用
- 如何知道析构函数中的堆栈损坏来自何处
- C++基于堆栈的构造函数/析构函数无法按预期工作
- C++为什么在堆栈中构造对象后立即调用析构函数
- 使用堆栈的非递归析构函数二叉搜索树
- 析构函数如何删除嵌套堆栈类型
- 构造函数/析构函数在堆栈上的调用顺序
- 受保护析构函数对象在堆vs堆栈上的分配