【问题解决】C++调用shared_from_this报错bad_weak_ptr解决方案

时间:2024-10-23 09:15:15

【问题解决】C++调用shared_from_this()报错bad_weak_ptr解决方案

一、问题背景

在 C++11 之前,通常使用 std::shared_ptr 来管理对象的生命周期,但如果一个对象需要在内部获取指向自身的 shared_ptr,就比较麻烦。直接构造一个 shared_ptr 会导致引用计数不正确,从而引发内存泄漏或悬空指针的问题。

因此,C++11 引入了 std::enable_shared_from_this,它提供了一种安全且高效的方式,让一个对象能够在内部获取指向自身的 shared_ptr

通过继承 std::enable_shared_from_this,类可以调用 shared_from_this() 函数来获取指向自身的 shared_ptr。这个函数会保证 shared_ptr 的引用计数是正确的,避免了手动管理引用计数的复杂性。

二、正常情况

正常情况下,在Test函数中使用shared_from_this();,编译执行成功,可以捕获符合生命周期的this指针。

#include <memory>

class Node : public std::enable_shared_from_this<Node> {
public:
    Node() {}
    ~Node() {}
    void Test() {
        auto sharedThis = shared_from_this();
    }
};

int main() {
    std::shared_ptr<Node> node1 = std::make_shared<Node>();
    node1->Test();
    return 0;
}

三、异常情况

  1. 构造函数中调用shared_from_this()
#include <memory>

class Node : public std::enable_shared_from_this<Node> {
public:
    Node() {
        auto sharedThis = shared_from_this();
    }
    ~Node() {}
    void Test() {}
};

int main() {
    std::shared_ptr<Node> node1 = std::make_shared<Node>();
    node1->Test();
    return 0;
}
  1. unique_ptr构造enable_shared_from_this对象
#include <memory>

class Node : public std::enable_shared_from_this<Node> {
public:
    Node() {}
    ~Node() {}
    void Test() {
        auto sharedThis = shared_from_this();
    }
};

int main() {
    std::unique_ptr<Node> node1 = std::make_unique<Node>();
    node1->Test();
    return 0;
}
  1. 裸指针构造enable_shared_from_this对象
#include <memory>

class Node : public std::enable_shared_from_this<Node> {
public:
    Node() {}
    ~Node() {}
    void Test() {
        auto sharedThis = shared_from_this();
    }
};

int main() {
    Node* node1 = new Node();
    node1->Test();
    return 0;
}

以上三种情况都能编译成功,但执行时报错:

terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr
Aborted (core dumped)

四、异常分析

  1. 查看c++ reference中std::bad_weak_ptr的描述:当shared_ptr指向一个已经被删除的对象时会抛出std::bad_weak_ptr异常。

    std::bad_weak_ptr is the type of the object thrown as exceptions by the constructors of std::shared_ptr that take std::shared_ptr as the argument, when the std::shared_ptr refers to an already deleted object.

  2. 查看shared_ptr.h头文件中的shared_from_this()源码和_M_weak_this定义。

public:
  shared_ptr<_Tp>
  shared_from_this()
  { return shared_ptr<_Tp>(this->_M_weak_this); }

  shared_ptr<const _Tp>
  shared_from_this() const
  { return shared_ptr<const _Tp>(this->_M_weak_this); }
mutable weak_ptr<_Tp>  _M_weak_this;
  1. 发现shared_from_this()实现就是将一个weak_ptr的this指针转换成shared_ptr指针的过程。

  2. 构造函数中调用shared_from_this()时,Node实例还未被构造,_M_weak_this还未生成,所以报错bad_weak_ptr

  3. unique_ptr构造enable_shared_from_this对象和裸指针构造enable_shared_from_this对象都不被std::shared_ptr管理,当调用shared_from_this()时,将导致未定义行为。

五、解决方案

  1. 对于构造函数中调用shared_from_this()的情况,应该避免在构造函数中调用shared_from_this(),解决办法即将相关逻辑移到函数中执行,在构造完成后调用相应函数以实现相同逻辑。
  2. 对于非unique_ptr构造enable_shared_from_this对象和裸指针构造enable_shared_from_this对象的情况,应使用std::make_sharedstd::shared_ptr实现相关函数的构造,使构造出的对象受std::shared_ptr管理。

六、参考文档

  1. C++ reference之std::bad_weak_ptr:https://en.cppreference.com/w/cpp/memory/bad_weak_ptr。
  2. C++源码之shared_ptr.h头文件。