1

I'm having a bit of an issue with C++ lambdas and variable capture (by reference). One lambda captures the variable to change its value while the other captures it to read the value. Everything is running on the same thread.

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
});

If it's any help, internally the lambdas are being boxed into C callbacks using void pointers. However, I doubt that's where the problem lies because, essentially, the two lambdas are going through the exact same process and one works while the other doesn't.

// 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);
}

SOLUTION

I gave the Cedar::Input and Cedar::Platform classes fields to store a copy of the lambdas.

// 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);
}
2
  • How are they being boxed into void pointers? That's actually probably where the problem is. A lambda with a capture can't be converted to a function pointer. Commented Dec 31, 2014 at 19:49
  • I updated the question with the boxing code. Commented Dec 31, 2014 at 19:56

1 Answer 1

1

You're storing a dangling pointer:

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
}

This is undefined behavior. You're doing the same thing in the other case too, it just happens to work there.

Sign up to request clarification or add additional context in comments.

1 Comment

I solved it by storing a copy of the event as a member variable and capturing a pointer to that instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.