【问题标题】:c++ captured reference to bool wrong valuec ++捕获对布尔错误值的引用
【发布时间】:2014-07-31 13:34:41
【问题描述】:

我通过引用 lambda 捕获本地 bool 值,并且第一次捕获该值时未分配该值(一些随机值)。为什么?

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

【问题讨论】:

  • 稍后调用按钮事件侦听器时,singleConfirmed 是否保留在堆栈中?
  • 不要创建自动的bool,而是创建std::shared_ptr<bool> 并按值捕获它。这将允许 lambda 保持 bool 活着。

标签: c++ c++11 lambda boolean


【解决方案1】:

提供的代码中没有足够的上下文来确定,但正如 sharth 在 cmets 中暗示的那样,问题几乎可以肯定是 singleConfirmed 是一个自动的局部变量,它已经超出范围(被销毁)调用 lambda 的时间,这意味着 lambda 将使用野生引用。为了解决这个问题,您需要使用在范围退出时不会被破坏的东西。这意味着动态分配。动态分配意味着您需要在 lambda 被销毁时解除分配。确保这一点的最简单方法是使用智能指针。综上所述,我的建议是将bool 存储在shared_ptr 中并按值捕获:

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

text 似乎是您按值捕获的某种指针,因此只要在 lambda 消失之前它没有得到 deleted 就可以了)

【讨论】:

  • 或更好,按值捕获bool 并将lambda 设为mutable
  • @newacct 我反对可变 lambda,因为它感觉像是在作弊。但我想,总而言之,捕获指向非常量对象的指针只是绕过 lambda 理想的另一种方式,它总是在给定相同输入的情况下产生相同的输出。
【解决方案2】:

正如 swarth 和 dlf 的评论所暗示的,lambda 几乎肯定是在局部变量 singleConfirmed 的范围之外运行的。 addTouchEventListener 的名称强烈暗示函数对象将被存储和执行以响应某些用户事件,而不是现在同步执行。

当 lambda 将在创建它的范围之外执行时,通过引用捕获变量是没有意义的,因为这些变量在执行时将超出范围,并且因此,使用引用是无效的。

相反,您应该按价值捕获。但是,默认情况下,值捕获的变量是const,因此您不能在 lambda 中对其进行赋值,因为您似乎想在此处执行此操作。您需要声明 lambda mutable 以使捕获的值变量非const

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 2017-05-27
    • 2019-04-14
    相关资源
    最近更新 更多