【问题标题】:double free or corruption with shared pointers共享指针双重释放或损坏
【发布时间】:2016-10-12 07:29:14
【问题描述】:

所以我的问题的本质是这样的:

//Big.h
class Big{
    public:
        int a, b;
};

//Mini.h
class Big;
class Mini{
    public:
        Mini(float a, shared_ptr<Big> ptb):ma(a), me(-a), ptb(ptb){};
        float ma, me;
        shared_ptr<Big> ptb;
};

//main
int main(){
    std::list<Mini> lm;
    if(true){ //Or some sub function or rutin
        Big big; big.a = 100; big.b = 200;
        Mini derp(5, shared_ptr<Big>(&big));
        lm.push_front(derp);
    }
  //Do something
};

编译正常,但在退出 main 时会出现“双重释放或损坏”(在完整程序中,这只是一个子函数)

我怀疑shared_ptrbig 在某个时候被释放,然后在退出主目录时又被释放,但我不确定也不知道如何修复它。有人可以解释一下这个错误的原因吗?

我红了我必须NULL 指向的指针,但我不知道在哪里。 或者也许我只是使用了错误的智能指针或类似的东西?

谢谢

【问题讨论】:

    标签: c++ pointers


    【解决方案1】:

    您正在构造一个shared_ptr,并带有一个指向堆栈上现有对象的指针。不要那样做;这不是shared_ptr 的用途。不应删除或释放普通堆栈对象。它指向的对象应该在堆上,即使用new 或等价物创建。

    创建shared_ptr 的推荐方法是通过make_shared

    auto p = make_shared<Big>();
    

    或老式的方式:

    shared_ptr<Big> p(new Big);
    

    【讨论】:

    • 只有一件事我不明白。 auto 关键字。我认为这只是要求编译器决定类型。是否有必要,或者我可以只制作 Big 类型吗?
    • 实际类型是 shared_ptr。我在那里使用 auto 只是为了省去写出来的麻烦,因为从表达式中可以清楚地看出类型。我一般认为当从右边的表达式中可以明显看出类型时使用 auto 是合理的,并且将其完整地写出来不会给读者任何新的信息。
    【解决方案2】:

    shared_ptr 管理的对象必须在动态范围内构造,即使用new 分配。

    Big big;
    big.a = 100;
    big.b = 200;
    
    Mini derp(5, shared_ptr<Big>(&big));
    

    在这里,您将指向在自动范围内构造的对象的指针推入shared_ptrshared_ptr 现在认为它拥有这个对象,它可以决定什么时候去delete 它。

    但是当自动作用域中的这个对象超出作用域并被销毁时,这将使shared_ptr 非常非常难过。

    使用new 构造此对象,而不是在自动范围内构造它。

    【讨论】:

    • 我建议默认使用make_shared,除非有理由不使用(使用weak_ptr/自定义删除器)
    【解决方案3】:

    shared_ptr 指向一个堆栈对象。您不能释放堆栈对象。以下是shared_ptr的使用方法:

    auto big = std::make_shared<Big>();
    big->a = 100;
    big->b = 200;
    Mini derp(5, big);
    

    【讨论】:

      【解决方案4】:

      要更正您的程序,您需要在堆上分配Big 对象。

      if(true){ //Or some sub function or rutin
              auto big_shared_ptr = std::make_shared<Big>();
              big->a = 100; big->b = 200;
              Mini derp(5, big_shared_ptr);
              lm.push_front(derp);
          }
      

      这样,当你的 if(true) 块返回以及 shared_ptr 被清理时,变量不会被破坏 - 这会导致双重释放。

      【讨论】:

        猜你喜欢
        • 2023-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多