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

问题描述:

我是一个SWE学习C++,并使用std ::的unique_ptr为headnext引用建立一个简单的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的工作方式?

+0

这看起来不像'std :: unique_ptr'的智能用法。持有'unique_ptr'意味着拥有对象的所有权。在链接列表中,节点不拥有下一个节点的所有权,它拥有本身包含的数据的所有权。 – Jack

+0

您可以发布您正在讨论的整个代码,以便其他人可以编译并查看会发生什么吗? – Ruslan

+0

当然! https://gist.github.com/manuelmenzella/0fd85280d5051abec2c7 不要太苛刻;) –

在你的榜样,你有确实递归,背后的真正原因是没有达到堆栈溢出可能是因为它是一个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声明断点和检查堆栈跟踪你清楚地看到这种行为是递归的:

enter image description here

的行为通过使用基本析构函数来跟踪~Node()何时返回也显示here

由于next节点在从析构函数返回之前必须销毁,这导致再次调用~Node()。这种行为将是相同的,通过使用原始指针并直接在析构函数中删除下一个指针,这实际上已经回答了here