c++ - 包含 std::function 回调的多个包装器的 std::vector 不起作用
问题描述
我正在编写一个MyTest
包含用于存储回调的 std::function<> 的包装器。包装器包含在tests
shared_ptr<> 的 std::vector 中。emplace_back 向量工作中的单个包装器,即可以触发 std::function 回调。如果向量中有两个对象,则只有最后一个对象回调有效。
这是我的课程:
typedef function<void(const uint64_t &)> CallBackFunc_t;
class MyWheel
{
private:
class test
{
private:
const CallBackFunc_t &callback;
public:
test(const CallBackFunc_t &cb);
bool work();
};
public:
vector<shared_ptr<test>> tests;
int addTest(const CallBackFunc_t &test_callback);
void spin(void);
};
class MyTest
{
private:
int handle = -1;
MyWheel &wheel;
public:
MyTest(MyWheel &whl);
int setCallback(const CallBackFunc_t &callback);
};
和来源。
MyWheel::test::test(const CallBackFunc_t &cb) : callback(cb)
{
}
bool MyWheel::test::work()
{
callback(0);
return true;
}
int MyWheel::addTest(const CallBackFunc_t &test_callback)
{
tests.emplace_back(new test(test_callback));
return (int)(test.size()-1);
}
void MyWheel::spin(void)
{
for(vector<shared_ptr<test>>::iterator test = tests.begin(); test != tests.end(); ++test)
{
(*test)->work();
}
}
MyTest::MyTest(MyWheel &whl) : wheel(whl)
{
};
int MyTest::setCallback(const CallBackFunc_t &callback)
{
if(handle < 0)
{
handle = wheel.addTest(callback);
}
return handle;
}
用法:
MyWheel wh;
MyTest t1(wh);
MyTest t2(wh);
t1.setCallback([&](const uint64_t &e) {
cout <<"1\r\n";
});
t2.setCallback([&](const uint64_t &e) {
cout <<"2\r\n";
});
while(true)
{
wh.spin();
}
我希望在运行时打印“1”和“2”,但只有“2”是......我做错了什么?
解决方案
您需要通过副本存储回调:
class test
{
private:
CallBackFunc_t callback; // <---- make a copy of callback
public:
test(const CallBackFunc_t &cb);
bool work();
};
现在您有未定义的行为,因为您正在存储对回调的引用,该回调在此表达式的末尾被销毁:
t1.setCallback([&](const uint64_t &e) {
cout <<"1\r\n";
}); // it causes dangling reference
如果您想保留对内部回调的引用,test
您需要在调用之前将它们创建为左值setCallback
:
std::function<void (const uint64_t& )> callback1 = [](const uint64_t &e) {
cout <<"1\r\n";
};
t1.setCallback(callback1);
std::function<void (const uint64_t& )> callback2 = [](const uint64_t &e) {
cout <<"2\r\n";
};
t2.setCallback(callback2);
推荐阅读
- assembly - RISC-V 指令将脏缓存行写入下一级缓存
- vlc - 使用 VLC 到 RTSP 流屏幕捕获转码为 MJPEG
- postgresql - 如何防止使用 postgresql 自动转换时区?
- javascript - 使用 [key, object] 值迭代映射
- reactjs - 无法从反应 pod 向服务 pod 发出请求
- azure - Azure ARM 模板:使用变量设置参数值
- azure - Azure Log Analytics - 将 FuncioAlias 更新/添加到 SavedSearch 查询
- nginx - Nginx 重定向带和不带端口
- php - 在php foreach循环中基于用户会话隐藏和显示按钮
- html - 使用 CSS 循环裁剪 iframe