C++ smart_ptr不会导致堆栈溢出?
问题描述:
我是一个SWE学习C++,并使用std ::的unique_ptr为head
和next
引用建立一个简单的LinkedList类。这是基本结构:C++ smart_ptr不会导致堆栈溢出?
template <class T>
struct LinkedListNode {
T value;
std::unique_ptr<LinkedListNode<T>> next;
// For debugging.
~LinkedListNode() {
std::cout << "destructed for value " << this->value << std::endl;
}
};
template <class T>
struct LinkedList {
std::unique_ptr<LinkedListNode<T>> head;
};
使用智能指针,我想到的是,当一个LinkedList实例被删除或超出范围,则head
将被删除,并且每个next
节点将递归也被删除。
而这正是发生了什么。但是,当处理真正的长列表(~20M节点)时,它仍然可以正常工作。不应该因堆栈溢出而崩溃吗?
为了非常粗略估计我的操作系统堆栈的大小,我写了下面的脚本:
int main() {
struct s {
static void p(int i) {
std::cout << i << std::endl;
p(i+1);
};
s::p(0);
}
而且它的迭代次数坠毁〜175K,比我能到20M节点要少得多之前解除分配。到底是怎么回事?我是否错过了unique_ptr的工作方式?
答
在你的榜样,你有确实递归,背后的真正原因是没有达到堆栈溢出可能是因为它是一个tail-call recursion可能进行优化,以迭代求解。
有了这个代码片段:
struct Node
{
int value;
std::unique_ptr<Node> next;
Node(int value, Node* next) : value(value), next(next) { }
~Node()
{
if (value == 0)
cout << "foo" << endl;
}
};
int main()
{
Node* node = new Node(0, nullptr);
for (int i = 1; i <= 5; ++i)
node = new Node(i, node);
delete node;
return 0;
}
通过放置在cout
声明断点和检查堆栈跟踪你清楚地看到这种行为是递归的:
的行为通过使用基本析构函数来跟踪~Node()
何时返回也显示here。
由于next
节点在从析构函数返回之前必须销毁,这导致再次调用~Node()
。这种行为将是相同的,通过使用原始指针并直接在析构函数中删除下一个指针,这实际上已经回答了here。
这看起来不像'std :: unique_ptr'的智能用法。持有'unique_ptr'意味着拥有对象的所有权。在链接列表中,节点不拥有下一个节点的所有权,它拥有本身包含的数据的所有权。 – Jack
您可以发布您正在讨论的整个代码,以便其他人可以编译并查看会发生什么吗? – Ruslan
当然! https://gist.github.com/manuelmenzella/0fd85280d5051abec2c7 不要太苛刻;) –