C++ smart_ptr不会导致堆栈溢出?

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的工作方式吗?

Jac*_*ack 2

在您的示例中,您确实有递归,其未达到堆栈溢出的真正原因可能是因为它是尾部调用递归,可以优化为迭代解决方案。

通过这段代码:

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()再次调用。通过使用原始指针并直接在析构函数中删除下一个指针,这种行为是相同的,这实际上已经在这里得到了回答。