STL容器保存智能指针并将this指针通过emplace传入STL容器所造成的致命问题(【double free or corruption (out)】和【bad_weak_ptr】)

我用std::queue保存了一个Message类型的智能指针(queue<shared_ptr<MessageA>),然后在Message类型中来将this指针插入队列,使用std::queue::push(this)不可以通过编译,而使用std::queue::emplace(this)却可以,因此便使得问题在pop()时出现:造成double free or corruption (out) 错误

#include<iostream>
#include<queue>
#include<memory>

using namespace std;

// 传递智能指针,有问题,因为std::queue::pop会析构/释放智能指针
static queue<shared_ptr<class MessageA>> QA;

// 传递裸指针,没问题,因为std::queue不会析构/释放裸指针
// static queue<class MessageA*> QA;

class MessageA {
public:
    explicit MessageA(int m): msg{m} {}

    void produce() {
        QA.emplace(this); //! pop时会出现错误:double free or corruption (out)
        cout << QA.front().use_count() << endl;
    }

    int msg;
};

int main() {
    auto messageA = std::make_shared<MessageA>(1);
    messageA->produce();
    QA.pop(); // error: double free or corruption (out)
}

试着用enable_shared_from_thisshared_from_this来解决:失败,pop时会出现异常:bad_weak_ptr

#include<iostream>
#include<queue>
#include<memory>

using namespace std;

// 传递智能指针,有问题,因为std::queue::pop会析构/释放智能指针
static queue<shared_ptr<class MessageB>> QB;

// 传递裸指针,没问题,因为std::queue不会析构/释放裸指针
// static queue<class MessageB*> QB;

// 试图使用enable_shared_from_this来解决:失败
class MessageB: enable_shared_from_this<MessageB> {
public:
    explicit MessageB(int m): msg{m} {}

    void produce() {
        QB.emplace(shared_from_this());  //! pop时会出现异常:bad_weak_ptr
    }

    int msg;
};

int main() {
    auto messageB = std::make_shared<MessageB>(2);
    messageB->produce();
    QB.pop(); // exception: bad_weak_ptr
}

最后发现,该问题本质上相当于:

int * a = new int{};
shared_ptr<int> a1{a};
shared_ptr<int> a2{a};

// 函数结束时析构shared_ptr,也会造成double free错误

这个问题相信用智能指针的人都知道不能这么做,应该在shared_ptr构造时new,而不是像上面这样,会使得引用计数为1而不是为2。

而最上面的代码却通过emplace(this),使用原生指针构造了一个智能指针,而这个智能指针不与任何指针共享引用计数,最后便会产生double free错误。

由于本人才疏学浅,目前还没找到解决办法(也懒得找),但是有一个结论是肯定的:不要将原生指针(特别是this)传递给智能指针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值