【问题标题】:Lambda not capturing variable correctlyLambda 未正确捕获变量
【发布时间】: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::InputCedar::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 转换为函数指针。
  • 我用装箱码更新了问题。

标签: c++ lambda closures


【解决方案1】:

你正在存储一个悬空指针:

void registerOnQuit(OnQuit event) {
    Cedar_Input_registerOnQuitC([](void *data)->void {
        (*(OnQuit *)data)();
    }, (void *)&event);  // <-- saving a pointer to event here

    // <-- event goes out of scope here
}

这是未定义的行为。在另一种情况下,您也在做同样的事情,它恰好在那里工作。

【讨论】:

  • 我通过将event 的副本存储为成员变量并捕获指向它的指针来解决此问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
相关资源
最近更新 更多