C++17弱绑定问题:如何用weak_from_this()实现安全回调捕获
正确实现C++17中基于weak_from_this()的弱捕获回调
嘿,咱们来拆解下这个问题——你用weak_from_this()没输出的核心原因其实是一个容易忽略的关键要求,和shared_from_this()的规则是一样的:你的对象必须被std::shared_ptr管理,weak_from_this()才能正常工作。如果对象没有被shared_ptr持有,weak_from_this()返回的是一个空的weak_ptr,后续lock()自然拿不到有效对象,回调逻辑也就不会执行了。
为什么C++14用shared_from_this()能正常工作?
你之前用shared_from_this()时,应该已经确保了对象是由std::shared_ptr创建和管理的(比如用make_shared),捕获shared_ptr会延长对象的生命周期,只要回调还存在,对象就不会被销毁,所以回调能正常执行。但切换到weak_from_this()后,如果对象没被shared_ptr管理,或者在回调执行前对象已经被销毁,weak_ptr.lock()就会失败,导致无输出。
正确的实现步骤与示例代码
下面是符合C++17规范的正确实现,核心是确保对象被shared_ptr管理,并且在回调中正确检查weak_ptr的有效性:
#include <iostream> #include <memory> #include <functional> #include <vector> // 必须继承enable_shared_from_this<T>,T是当前类名 class ProcessingFrame : public std::enable_shared_from_this<ProcessingFrame> { public: // 注册回调到事件列表 void registerCallback(std::vector<std::function<void()>>& eventList) { // 获取当前对象的weak_ptr,用于弱捕获 auto weakSelf = weak_from_this(); eventList.push_back([weakSelf]() { // 尝试将weak_ptr转换为shared_ptr,检查对象是否存活 if (auto self = weakSelf.lock()) { self->executeCallbackLogic(); } else { std::cout << "Warning: Callback skipped - object has been destroyed\n"; } }); } // 回调实际执行的逻辑 void executeCallbackLogic() { std::cout << "Callback executed successfully: Object is alive\n"; } }; int main() { std::vector<std::function<void()>> events; // 测试场景1:对象在回调执行前被销毁 { auto frame = std::make_shared<ProcessingFrame>(); frame->registerCallback(events); // 离开作用域,frame被销毁,对象生命周期结束 } std::cout << "=== Testing destroyed object ===\n"; for (auto& cb : events) { cb(); } // 测试场景2:对象在回调执行时仍然存活 auto frameAlive = std::make_shared<ProcessingFrame>(); frameAlive->registerCallback(events); std::cout << "\n=== Testing alive object ===\n"; for (auto& cb : events) { cb(); } return 0; }
关键注意点
- 必须继承
std::enable_shared_from_this<T>:这是获取weak_from_this()的前提,编译器会为你的类注入相关的指针管理逻辑。 - 对象必须由
std::shared_ptr创建:绝对不能直接在栈上创建对象(比如ProcessingFrame frame;),栈对象无法被shared_ptr管理,weak_from_this()会返回空的weak_ptr。必须用std::make_shared或者std::shared_ptr<ProcessingFrame>(new ProcessingFrame())来创建实例。 - 回调中必须检查
lock()的结果:lock()会返回一个shared_ptr,如果对象已经销毁,返回的是空的shared_ptr,此时不能执行任何对象相关的逻辑。 - 编译选项:用g++ 6.3.0编译时,需要指定
-std=c++1z或者-std=c++17来启用C17特性(g6.3对C++17的支持用c++1z作为参数,后续版本才统一用c++17)。
为什么你的原代码无输出?
大概率是以下两种情况之一:
- 你的对象是栈上创建的,没有被
shared_ptr管理,导致weak_from_this()返回空weak_ptr,lock()失败后没有执行回调逻辑。 - 在回调执行前,对象已经被销毁,
weak_ptr无法锁定到有效对象,所以没有输出。
内容的提问来源于stack exchange,提问作者Jens Munk
相关产品推荐
相关产品推荐

