问题背景:
[this, listener]()
,通过值捕获就能正常运行问题:如下这段C++代码运行会报错。报错行数是"test_listener_->OnReceiver();"。错误信息有两个
我就想知道我写成按照引用捕获为啥会出错。出错的原因是什么?而且在使用 test_listener_ 代理前我都打印了地址,都是正确的。感谢您的指点 感激不尽 祝您工作顺利
#include <iostream>
#include "TaskProcessor.h"
using namespace CallPlugin;
class TestListener {
public:
virtual ~TestListener() {}
virtual void OnReceiver() = 0;
};
class TestManager {
public:
TestManager():task_processor_(std::make_unique<TaskProcessor>()) {
std::cout << "TestManager()" << std::endl;
}
~TestManager() {
std::cout << "~TestManager()" << std::endl;
}
void SetListener(TestListener* listener) {
task_processor_->SyncTask(FROM_HERE, [&](){
test_listener_ = listener;
std::cout << "-----SetListener-->>test_listener_: "<<(void *)test_listener_<< std::endl;
});
}
void OnReceiver() {
task_processor_->SyncTask(FROM_HERE, [&](){
std::cout << "-----OnReceiver-->>test_listener_: "<<(void *)test_listener_<< std::endl;
test_listener_->OnReceiver();
});
}
private:
TestListener* test_listener_;
std::unique_ptr<TaskProcessor> task_processor_;
};
class ListenerImpl : public TestListener {
public:
ListenerImpl() {
std::cout<<"ListenerImpl()"<<std::endl;
}
~ListenerImpl() override {
std::cout<<"~ListenerImpl()"<<std::endl;
}
void OnReceiver() override {
std::cout<<"ListenerImpl-->OnReceiver"<<std::endl;
}
};
int main() {
ListenerImpl* listenerImpl = new ListenerImpl();
TestManager testManager;
testManager.SetListener(listenerImpl);
testManager.OnReceiver();
std::cout << "sleep_for"<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
delete listenerImpl;
std::cout << "Hello, World!" << std::endl;
return 0;
};
在lambada表达式中使用[&]进行按引用捕获会导致test_listener_的生命周期被延长,从而导致错误。
具体来说,[&]表示捕获外部作用域中的所有变量,并以引用的方式捕获。这会导致lambada表达式中捕获的变量的生命周期被延长到lambda表达式的生命周期。
但是在本例中,test_listener_是一个指针,它指向的对象ListenerImpl是在堆上分配的,由main函数负责delete释放。而lambda表达式捕获了test_listener_指针,使其生命周期延长,导致在main函数delete listenerImpl之后,test_listener_指针成为了悬垂指针,从而出现错误。
解决方法是不要使用[&]进行按引用捕获,可以用[=]进行按值捕获,或者指定只捕获test_listener_指针,如[test_listener_]。这样就能避免test_listener_的生命周期被无意间延长。
另外在C++中,使用new分配的对象最好结合智能指针来管理生命周期,避免手工delete带来的问题。
所以综合来说,建议的修改方案是: