对 linked_list 使用 shared_ptr 在析构函数中给出 stackoverflow
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();
}
由于调用了 aList
析构函数 (RAII),因此在离开 test_destroy()
作用域时会产生计算溢出。为了销毁 aList
,它调用了 next
的析构函数,依此类推,对于足够大的列表,这显然会导致 Whosebug。
我找不到任何有效的方法来解决这个问题。理想的情况是在移动到 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>();
};
NodeTest
的析构函数调用 NodeTest::next
的析构函数,后者递归调用另一个 NodeTest
析构函数,依此类推,直到堆栈耗尽。出于这个原因,不应将智能指针用于链接节点。
在这种情况下,您应该管理手动删除的节点,因为析构函数调用析构函数调用析构函数.....
看一下演讲CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”
我正在尝试使用 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();
}
由于调用了 aList
析构函数 (RAII),因此在离开 test_destroy()
作用域时会产生计算溢出。为了销毁 aList
,它调用了 next
的析构函数,依此类推,对于足够大的列表,这显然会导致 Whosebug。
我找不到任何有效的方法来解决这个问题。理想的情况是在移动到 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>();
};
NodeTest
的析构函数调用 NodeTest::next
的析构函数,后者递归调用另一个 NodeTest
析构函数,依此类推,直到堆栈耗尽。出于这个原因,不应将智能指针用于链接节点。
在这种情况下,您应该管理手动删除的节点,因为析构函数调用析构函数调用析构函数.....
看一下演讲CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”