C++:捕获 shared_from_this()和捕获this的区别

两种方法的主要区别在于对象的生命周期管理以及捕获方式的不同。以下是对两种方法的详细对比:


第一种:捕获 shared_from_this() 的方法

event.subscribe([self = shared_from_this()]() {
    std::cout << "Event triggered, object is alive." << std::endl;
    self->onEvent();
});
特点:
  1. 对象生命周期管理

    • 使用 shared_from_this() 捕获当前对象的 std::shared_ptr,保证对象在事件回调执行期间不会被销毁。
    • 即使外部没有对对象的引用,self 持有一个 shared_ptr,延长了对象的生命周期。
    • 适用于需要确保对象在事件发生时仍然有效的场景。
  2. 线程安全性

    • 如果事件回调可能在多线程环境中执行,这种方式可以避免悬空指针的风险。
  3. 对象有效性保障

    • 通过 shared_ptr 持有,可以避免事件触发时对象已被销毁的问题。

第二种:捕获 this 指针的方法

event.subscribe([this]() { 
    std::cout << "Event triggered, object is alive." << std::endl;
    this->onEvent(); 
});
特点:
  1. 生命周期依赖 this

    • 直接捕获 this 指针,依赖于调用 subscribe 时对象的生命周期。
    • 如果对象在事件触发之前被销毁,则调用 onEvent 会导致未定义行为(悬空指针)。
  2. 效率较高

    • 不需要额外的 shared_ptr 管理,直接捕获 this,开销更低。
    • 适用于生命周期完全受控、确保对象在事件回调中一定有效的场景。
  3. 风险

    • 如果对象在事件触发前已经被销毁,就会导致悬空指针错误,因此适合更受控的环境。

适用场景对比

方法优点缺点适用场景
捕获 shared_from_this()确保对象生命周期,安全性高。可用于异步或多线程环境,避免悬空指针。引入了 shared_ptr,增加了一些开销;要求对象继承 std::enable_shared_from_this异步事件、跨线程回调,或者在事件触发期间需要确保对象存活时。
捕获 this 指针效率高,简单直接,无需 shared_ptr 的额外管理。如果对象生命周期不受控(可能在事件触发前销毁),会导致悬空指针,容易出错。对象生命周期受控的情况下(如事件和对象生命周期严格同步,或者对象销毁前确保事件解绑)。

代码示例

捕获 shared_from_this() 的安全示例:
class Event;
class MyObject : public std::enable_shared_from_this<MyObject> {
public:
    void onEvent() {
        std::cout << "Event handled by shared_from_this!" << std::endl;
    }

    void subscribeToEvent(Event& event) {
        event.subscribe([self = shared_from_this()]() {
            std::cout << "Event triggered, object is alive." << std::endl;
            self->onEvent();
        });
    }
};
捕获 this 的受控示例:
class MyObject {
public:
    void onEvent() {
        std::cout << "Event handled by this pointer!" << std::endl;
    }

    void subscribeToEvent(Event& event) {
        event.subscribe([this]() {
            std::cout << "Event triggered, ensure object is valid." << std::endl;
            this->onEvent();
        });
    }
};

总结:

  • 如果对象生命周期由 std::shared_ptr 管理,建议使用 shared_from_this(),因为它可以确保对象在回调中存活。
  • 如果对象生命周期完全受控,且明确保证事件回调执行时对象一定存活,可以选择效率更高的 捕获 this
### C++ `std::shared_ptr` `std::make_shared` 的用法及区别 #### 使用场景与基本功能 `std::shared_ptr` 是一种智能指针,用于管理动态分配的对象。多个 `std::shared_ptr` 可以指向同一个对象,并通过引用计数来自动释放资源[^1]。 ```cpp #include <memory> int main() { std::shared_ptr<int> ptr(new int(42)); } ``` 而 `std::make_shared<T>` 函数提供了一种更高效的方式创建共享指针。它不仅减少了代码量,还提高了性能,因为可以一次性完成控制块对象的内存分配。 ```cpp #include <memory> int main() { auto ptr = std::make_shared<int>(42); } ``` #### 性能差异 当使用 `new` 创建对象并传递给 `std::shared_ptr` 构造函数时,会发生两次独立的内存分配:一次是为了存储实际数据,另一次则是为了保存引用计数信息。这可能导致额外开销以及较差的缓存局部性。 相反,`std::make_shared` 能够在同一块连续内存区域中同时分配这两个部分的空间,从而减少碎片化并提高访问速度。此外,在某些情况下还能省去不必要的拷贝操作。 #### 安全性异常处理 如果构造参数抛出了异常,则由 `std::make_shared` 分配的所有资源都将被安全清理;而对于显式调用 `new` 来初始化 `std::shared_ptr` 的情况来说,可能会存在潜在的风险——即在捕获到异常之前已经发生了泄漏。 综上所述,推荐优先考虑使用 `std::make_shared` 来代替直接利用 `new` 表达式的做法,除非有特殊需求或限制条件不允许这样做。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值