繁体   English   中英

在破坏期间使用std :: shared_ptr的Segfault可能是由于堆栈上的函数调用太多

[英]Segfault using std::shared_ptr during destruction likely due to too many function calls on the stack

以下代码编译并运行正常:

#include <memory>
struct MyTree {
    std::shared_ptr <MyTree> left;
    std::shared_ptr <MyTree> right;
    int val;
    MyTree(
        std::shared_ptr <MyTree> left_,
        std::shared_ptr <MyTree> right_,
        int val_
    ) : left(left_), right(right_), val(val_) {};
};
int main() {
    std::shared_ptr <MyTree> t(
        new MyTree( std::shared_ptr <MyTree>(),
                    std::shared_ptr <MyTree>(),
                    0)
    );  
    for(int i=0;i<10000;i++) {
        t.reset(new MyTree(t,t,0));
    }
}

但是,当for循环从10000更改为100000时,我收到段错误。 查看gdb中的结果,看起来像std :: shared_ptr中的垃圾收集调用的析构函数会创建一个数千深的回溯。 因此,我认为段错是由于函数调用从堆栈中耗尽。 我有两个问题。 首先,这是对segfault的正确评估吗? 其次,如果是这样,是否有一种很好的方法来管理自定义数据结构,例如需要进行垃圾回收的树,但可能非常大。 谢谢。

这通常不是问题,因为通常你保持树平衡,深度为O(lg N)。

相反,你得到了一个奇怪的单链表,每个指针都有一个副本。 那是......奇怪的。

一个真正的单链表将是非常深的递归,但可能会受益于尾调用优化而不会耗尽堆栈。

您遇到的问题对于混合两种数据结构而言非常独特。 哪个没有我能看到的好处。

您的评估对我来说完全正确。 看起来删除子子树的递归调用超过了yoru堆栈大小。 这与shared_ptr无关,但我预计数据结构上的任何递归算法也会以相同的方式失败。

如果可能在您的平台上,处理大型结构需求的最简单方法就是增加堆栈的大小(例如ulimit )以允许自然递归算法运行。

如果那是不可能的,那么你将不得不自己遍历节点,将遍历的结果存储到某种容器中,这样你就可以切割子节点而不需要对树结构进行全深度遍历。

这看起来像是滥用std::shared_ptr 还有一些非常糟糕的命名:你的类MyTree不是一棵树,而只是一个节点。 树应该是一个单独的类,并应删除其析构函数中的所有节点。

话虽如此,对于手头的问题,这不会有太大变化。 你以递归方式访问树上的节点(关于唯一有意义的方法),如果你让树太深,堆栈就会溢出,无论访问是否是隐式的(通过std::shared_ptr的析构函数调用std::shared_ptr )或显式。 创建这样的树是没有意义的,因为开始破坏它之前创建一个无法访问其节点的树是没有意义的。

编辑:

在评论中考虑垃圾收集的讨论。 使用Boehm收集器或其他一些垃圾收集器,将解决释放元素的问题。 但它仍然不允许你在释放之前访问它们,所以这样的树仍然无用。 (我认为在C ++中有很强的支持垃圾收集的论据,但这不是其中之一。)

我认为这种类型的错误可以在没有shared_ptr的情况下重现。 这基本上是一个很长的递归调用。 好的,我刚刚创建并删除了一半的树但是......

struct MyTree {
    MyTree *left;
    int val;
    MyTree()
    {
      left = 0;
    }
    MyTree(MyTree *left_)
     : left(left_) {};

    ~MyTree()
    {
      delete left;
    }
};
int main() {
    MyTree *t = new MyTree();
    for(int i=0;i<100000;i++) {
      t = new MyTree(t);
    }
    delete t;
}

只需在100000之后再添加一个零,就会得到相同的错误消息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM