Man*_*lla 5 c++ stack pointers overflow unique-ptr
我是SWE学习C++,并使用std :: unique_ptr作为head和的引用构建一个简单的LinkedList类next.这是基本结构:
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;
};
Run Code Online (Sandbox Code Playgroud)
使用智能指针,我希望当LinkedList实例被删除或超出范围时,head将被删除,并且每个next节点也将被递归删除.
这正是发生的事情.但是,当使用很长的列表(大约20M节点)时,它仍然可以正常工作.不应该因堆栈溢出而崩溃吗?
为了非常粗略地估计我的操作系统堆栈的大小,我编写了以下脚本:
int main() {
struct s {
static void p(int i) {
std::cout << i << std::endl;
p(i+1);
};
s::p(0);
}
Run Code Online (Sandbox Code Playgroud)
并且它在迭代次数~175K时崩溃,远远低于之前我能够解除分配的20M节点.到底是怎么回事?我错过了unique_ptr的工作方式吗?
在您的示例中,您确实有递归,其未达到堆栈溢出的真正原因可能是因为它是尾部调用递归,可以优化为迭代解决方案。
通过这段代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
通过在语句上放置断点cout并检查堆栈跟踪,您可以清楚地看到该行为是递归的:
此处还通过使用基本析构函数来跟踪返回时间来显示该行为~Node()。
由于在next从析构函数返回之前必须销毁该节点,这会导致~Node()再次调用。通过使用原始指针并直接在析构函数中删除下一个指针,这种行为是相同的,这实际上已经在这里得到了回答。