简体   繁体   中英

c++ captured reference to bool wrong value

I capture local bool value by reference to lambda and the first time it gets captured the value is unassigned (some random value). Why?

bool singleConfirmed=false;
        button->addTouchEventListener([text, &singleConfirmed](Ref*, Widget::TouchEventType type)
        {
            if (type != Widget::TouchEventType::ENDED) return;
            if (!singleConfirmed)
            {
                cocostudio::ActionManagerEx::getInstance()->playActionByName(R_tutorialDialog.c_str(), "MoveToTop");
                text->setString(G_str("Tutorial_Single/Multiplayer"));
                singleConfirmed=true;
                return;
            }
            else
            {
                cocostudio::ActionManagerEx::getInstance()->playActionByName(R_tutorialDialog.c_str(), "SwipeToLeft");
                text->setString(G_str("Tutorial_Single/Multiplayer"));
                return;
            }
        });

There's not quite enough context in the provided code to be certain, but as sharth hinted in the comments, the problem is almost certainly that singleConfirmed is an automatic, local variable that has gone out of scope (been destroyed) by the time the lambda is invoked, which means the lambda will be working with a wild reference. To solve this, you need to use something that won't be destroyed when the scope exits. That means dynamic allocation. Dynamic allocation means you'll need to deallocate when the lambda is destroyed. The simplest way to ensure that is to use a smart pointer. Putting that all together, my suggestion is to store the bool in a shared_ptr and capture it by value:

auto singleConfirmed = std::make_shared<bool>(false);
button->addTouchEventListener([text, singleConfirmed](Ref*, Widget::TouchEventType type)
{
   // ...
}

( text appears to be some sort of pointer that you're capturing by value, so that should be ok as long as it doesn't get delete d before the lambda goes away)

As swarth's and dlf's comment suggest, the lambda is almost certainly being run outside the scope of the local variable singleConfirmed . The name of addTouchEventListener strongly suggests that the function object will be stored and executed in response to some user event later, and not executed now synchronously.

When a lambda is going to be executed out of the scope in which it was created, it doesn't make sense to capture variables by reference, because those variables are going to be out of scope by the time it's executed, and therefore, using the reference is invalid.

Instead, you should capture by value. However, by default, value-captured variables are const , so you cannot assign to it inside the lambda, as it seems you want to do here. You need to declare the lambda mutable to make the value-captured variables non- const :

bool singleConfirmed = false;
button->addTouchEventListener(
    [text, singleConfirmed](Ref*, Widget::TouchEventType type) mutable {
        // everything in here stays the same
    })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM