共享指针出现双重释放或破坏问题

7

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

//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
};

编译没问题,但在退出主函数时出现“double free or corruption”错误(在完整程序中仅为子函数)。
我怀疑shared_ptrbig的应用会在某个时刻被释放,然后在退出main时再次释放,但我不确定也不知道如何修复它。能有人请解释一下这个错误的原因吗?
我看到我需要NULL指针,但我不知道在哪里。 或者我可能只是使用了错误的智能指针之类的东西?
谢谢
4个回答

8
你正在使用指向栈上现有对象的指针构造一个shared_ptr。不要这样做,因为这不是shared_ptr的正确使用方式。普通的栈对象永远不应该被删除或释放。它所指向的对象应该在堆上,即使用new或等价方法创建。
创建shared_ptr的推荐方式是通过make_shared函数:
auto p = make_shared<Big>();

或者采用传统的方式:
shared_ptr<Big> p(new Big);

只有一件事我不明白,那就是 auto 关键字。我以为它只是让编译器决定类型的。它是必需的吗?还是我可以直接使用类型 Big - Purin Lord
实际类型是 shared_ptr<Big>。我在那里使用 auto 只是为了节省写出来的麻烦,因为类型从表达式中很清楚。我通常认为,在右侧表达式中类型很明显,并且完全写出来不会给读者带来任何新信息时使用 auto 是合理的。 - Ross Smith

4

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

Big big;
big.a = 100;
big.b = 200;

Mini derp(5, shared_ptr<Big>(&big));

在这里,你正在将在自动作用域中构造的对象的指针推入shared_ptr中。现在,shared_ptr认为它拥有此对象,并且它决定何时将其delete
但是当此自动作用域中的对象超出范围并被销毁时,这将使这个shared_ptr非常非常难过。
请使用new来构造此对象,而不是在自动作用域中进行构造。

我建议默认使用make_shared,除非有理由不使用(如使用weak_ptr/自定义删除器) - krzaq

1

shared_ptr指向一个堆栈对象。您不能释放堆栈对象。以下是如何使用shared_ptr

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

1
为了修正你的程序,你需要在堆上分配你的 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被清理时,变量不会被销毁 - 这将导致双重释放。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接