【发布时间】:2014-12-31 19:43:33
【问题描述】:
我在使用 C++ lambda 和变量捕获(通过引用)时遇到了一点问题。一个 lambda 捕获变量以更改其值,而另一个捕获它以读取值。一切都在同一个线程上运行。
bool isRunning = true; // variable to be captured
Cedar::Input input;
input.registerOnQuit([&]()->void {
isRunning = false; // wrong address, value is constrained to lambda
});
Cedar::Platform platform;
platform.run([&](double t, double dt)->bool {
input.pump(); // internally fires the handler passed to registerOnQuit()
return isRunning; // correct address
});
如果有任何帮助,内部将使用void 指针将 lambda 封装到 C 回调中。但是,我怀疑这就是问题所在,因为从本质上讲,这两个 lambda 正在经历完全相同的过程,一个有效而另一个没有。
// boxes the broken lambda
using OnQuit = std::function<void()>;
void registerOnQuit(OnQuit event) {
Cedar_Input_registerOnQuitC([](void *data)->void {
(*(OnQuit *)data)();
}, (void *)&event);
}
// boxes the working lambda
using Hook = std::function<bool(double, double)>;
void run(Hook hook) {
Cedar_Platform_runC([](double t, double dt, void *data)->bool {
return (*(Hook *)data)(t, dt);
}, (void *)&hook);
}
解决方案
我提供了 Cedar::Input 和 Cedar::Platform 类字段来存储 lambda 的副本。
// fix to Cedar::Platform::run() is similar
using OnQuit = std::function<void()>;
void registerOnQuit(OnQuit event) {
m_onQuit = event;
Cedar_Input_registerOnQuitC([](void *data)->void {
(*(OnQuit *)data)();
}, (void *)&m_onQuit);
}
【问题讨论】:
-
它们是如何被装箱成空指针的?这实际上可能是问题所在。无法将带有捕获的 lambda 转换为函数指针。
-
我用装箱码更新了问题。