C++11:enable_shared_from_this

std::enable_shared_from_this 是C++中一个模板类,用于在类中实现从shared_ptr安全管理自身实例的功能。当类继承此模板后,可以安全地在成员函数中生成新的shared_ptr实例,共享原有的所有权。错误的做法如直接返回this或shared_ptr(this)会导致引用计数错误。正确使用是通过调用shared_from_this()。这个特性常在异步调用中确保对象在异步操作期间保持存活。

              enable_shared_from_this是一个模板类,定义于头文件<memory>,其原型为:

Enable shared_from_this

Base class that enables the shared_from_this member function in derived classes.

The class provides functionality that allows objects of derived classes to create instances of shared_ptr pointing to themselves and sharing ownership with existing shared_ptr objects.

Notice that simply returning shared_ptr<T>(this) would be problematic, since that would create a different ownership group.

enable_shared_from_this - C++ Reference

  std::enable_shared_from_this 能让一个对象(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, ... ) ,它们与 pt 共享对象 t 的所有权。
       若一个类 T 继承 std::enable_shared_from_this<T> ,则会为该类 T 提供成员函数: shared_from_this 。 当 T 类型对象 t 被一个为名为 pt 的 std::shared_ptr<T> 类对象管理时,调用 T::shared_from_this 成员函数,将会返回一个新的 std::shared_ptr<T> 对象,它与 pt 共享 t 的所有权。
        一.使用场合

            当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。

        1.为何不直接传递this指针

        使用智能指针的初衷就是为了方便资源管理,如果在某些地方使用智能指针,某些地方使用原始指针,很容易破坏智能指针的语义,从而产生各种错误。

        2.可以直接传递share_ptr<this>么?

          答案是不能,因为这样会造成2个非共享的share_ptr指向同一个对象,未增加引用计数导对象被析构两次。例如:     
#include <memory>
#include <iostream>
 
class Bad
{
public:
    std::shared_ptr<Bad> getptr() {
        return std::shared_ptr<Bad>(this);
    }
    ~Bad() { std::cout << "Bad::~Bad() called" << std::endl; }
};
 
int main()
{
    // 错误的示例,每个shared_ptr都认为自己是对象仅有的所有者
    std::shared_ptr<Bad> bp1(new Bad());
    std::shared_ptr<Bad> bp2 = bp1->getptr();
    // 打印bp1和bp2的引用计数
    std::cout << "bp1.use_count() = " << bp1.use_count() << std::endl;
    std::cout << "bp2.use_count() = " << bp2.use_count() << std::endl;
}  
        输出结果如下:

        正确的实现如下: 
#include <memory>
#include <iostream>
 
struct Good : std::enable_shared_from_this<Good> // 注意:继承
{
public:
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
    ~Good() { std::cout << "Good::~Good() called" << std::endl; }
};
 
int main()
{
    // 大括号用于限制作用域,这样智能指针就能在system("pause")之前析构
    {
        std::shared_ptr<Good> gp1(new Good());
        std::shared_ptr<Good> gp2 = gp1->getptr();
        // 打印gp1和gp2的引用计数
        std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;
        std::cout << "gp2.use_count() = " << gp2.use_count() << std::endl;
    }
    system("pause");

}

        二.为何会出现这种使用场合

        因为在异步调用中,存在一个保活机制,异步函数执行的时间点我们是无法确定的,然而异步函数可能会使用到异步调用之前就存在的变量。为了保证该变量在异步函数执期间一直有效,我们可以传递一个指向自身的share_ptr给        异步函数,这样在异步函数执行期间share_ptr所管理的对象就不会析构,所使用的变量也会一直有效了(保活)。

Boost.Asio C++ 网络编程之五:TCP回显客户端/服务端_草上爬的博客-优快云博客
 

<think>好的,我现在需要解释一下`std::enable_shared_from_this`这个C++标准库中的类。用户可能对它的用途和用法不太清楚,所以我要一步步理清楚思路,确保回答准确且易于理解。 首先,我应该回忆一下这个类的基本作用。记得它主要用于解决当一个类的对象已经被某个`shared_ptr`管理时,如何安全地获取该对象的另一个`shared_ptr`的问题。这样可以避免创建多个控制块,防止未定义行为,比如双重删除。 接下来,我需要考虑用户可能遇到的问题场景。比如,在一个类的成员函数中,如果对象已经被`shared_ptr`管理,想要传递自身的`shared_ptr`给其他函数,如果直接使用`this`指针创建新的`shared_ptr`,会导致两个独立的`shared_ptr`指向同一个对象,各自拥有一个引用计数,这样当其中一个计数归零时,对象会被删除,另一个就成了悬垂指针,导致问题。 然后,`std::enable_shared_from_this`的解决方案。这个类提供了一个成员函数`shared_from_this()`,返回当前对象的`shared_ptr`,并且这个`shared_ptr`与之前管理该对象的`shared_ptr`共享同一个控制块。因此,正确使用可以避免创建多个控制块,确保引用计数正确。 接下来,我需要说明如何使用这个类。用户需要让他们的类公有继承自`std::enable_shared_from_this<T>`,其中T是类自身的名字。然后,在需要获取`shared_ptr`的地方调用`shared_from_this()`方法。需要注意的是,这种方法只能在对象已经被`shared_ptr`管理的情况下使用,否则会抛出异常。 可能还需要提到构造函数和析构函数中的使用限制,因为在构造和析构过程中,对象可能尚未被`shared_ptr`完全管理,此时调用`shared_from_this()`会导致未定义行为。 另外,应该给出一个简单的代码示例,说明如何正确继承和使用。例如: class MyClass : public std::enable_shared_from_this<MyClass> { public: void doSomething() { std::shared_ptr<MyClass> self = shared_from_this(); // 使用self } }; 同时,必须强调在创建对象时,必须使用`std::make_shared`或者直接通过`std::shared_ptr`的构造函数,而不是裸指针,否则`enable_shared_from_this`无法正确工作。 可能还需要说明内部实现的大致原理,即`enable_shared_from_this`内部保存了一个指向控制块的弱指针,当调用`shared_from_this()`时,会尝试将这个弱指针提升为`shared_ptr`,如果成功则返回,否则抛出异常。 最后,总结一下使用注意事项:必须公有继承,对象必须已经被`shared_ptr`管理,不能在构造函数和析构函数中使用,以及必须正确创建`shared_ptr`实例。 要确保语言通俗易懂,结构清晰,分步骤解释,并给出示例帮助理解。同时,检查是否有遗漏的关键点,比如为什么不能直接使用this创建shared_ptr,以及enable_shared_from_this如何解决这个问题。</think>`std::enable_shared_from_this` 是 C++ 标准库中的一个工具类,用于解决 **对象需要安全地获取自身的 `std::shared_ptr`** 的问题。以下逐步解释其作用、原理及用法: --- ### 1. **问题背景** 假设有一个类 `MyClass`,其对象被 `std::shared_ptr` 管理。在某个成员函数中,若需要将对象自身的 `std::shared_ptr` 传递给其他函数,直接使用 `this` 指针构造新的 `std::shared_ptr` 会导致错误: ```cpp class MyClass { public: void foo() { // 错误!会创建独立的控制块,导致双重释放 std::shared_ptr<MyClass> invalid_ptr(this); } }; int main() { auto obj = std::make_shared<MyClass>(); obj->foo(); // 调用后,invalid_ptr 和 obj 各自引用计数为1,导致重复析构 } ``` 此时,`invalid_ptr` 和 `obj` 指向同一对象,但引用计数独立。当两者超出作用域时,会分别析构对象,引发未定义行为。 --- ### 2. **解决方案:`enable_shared_from_this`** 通过继承 `std::enable_shared_from_this<T>`,类可以安全地获取与已有 `std::shared_ptr` 共享控制块的指针。 #### 步骤 1:公有继承 ```cpp class MyClass : public std::enable_shared_from_this<MyClass> { public: void foo() { // 正确!共享现有控制块 std::shared_ptr<MyClass> valid_ptr = shared_from_this(); } }; ``` #### 步骤 2:必须通过 `shared_ptr` 管理对象 ```cpp int main() { auto obj = std::make_shared<MyClass>(); // 必须用 make_sharedshared_ptr 构造函数 obj->foo(); // 安全使用 shared_from_this() } ``` --- ### 3. **核心原理** - `enable_shared_from_this` 内部保存了一个 **弱引用 (`weak_ptr`)**,指向当前对象的所有权控制块。 - 当调用 `shared_from_this()` 时,会尝试将弱引用提升为 `shared_ptr`: - 若对象已被 `shared_ptr` 管理,提升成功,返回共享控制块的 `shared_ptr`。 - 否则,抛出 `std::bad_weak_ptr` 异常。 --- ### 4. **使用注意事项** 1. **必须公有继承** 确保 `enable_shared_from_this` 能通过 CRTP 模式访问派生类的成员。 2. **对象必须已被 `shared_ptr` 管理** 未通过 `shared_ptr` 构造的对象调用 `shared_from_this()` 会抛出异常。 3. **禁止在构造/析构函数中使用** 构造和析构期间,对象可能尚未被 `shared_ptr` 完全托管,此时调用 `shared_from_this()` 会导致未定义行为。 --- ### 5. **典型应用场景** - **回调函数**:将对象自身的 `shared_ptr` 传递给异步回调。 - **链式调用**:在成员函数中返回当前对象的 `shared_ptr`。 - **观察者模式**:让观察者持有被观察对象的 `shared_ptr`。 --- ### 6. **代码示例** ```cpp #include <memory> #include <iostream> class MyClass : public std::enable_shared_from_this<MyClass> { public: void process() { // 获取当前对象的 shared_ptr auto self = shared_from_this(); std::cout << "Use count: " << self.use_count() << std::endl; } }; int main() { auto obj = std::make_shared<MyClass>(); obj->process(); // 输出 Use count: 2(obj 和 self 共享) return 0; } ``` --- ### 7. **总结** - **作用**:安全获取与现有 `shared_ptr` 共享控制块的指针,避免多控制块导致的未定义行为。 - **关键点**:公有继承、必须通过 `shared_ptr` 管理对象、禁止在构造/析构中使用。 - **底层机制**:通过内部弱引用 (`weak_ptr`) 提升为 `shared_ptr`。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值