首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Lambda捕获意外变量。

Lambda捕获意外变量。
EN

Stack Overflow用户
提问于 2016-05-16 23:08:14
回答 2查看 127关注 0票数 0

我试图弄清楚lambda是如何在C++中工作的。

奇怪的事情发生了。太奇怪了,我不知道怎么正确地描述它。我试过搜索几个关键词,但没有发现任何提到这种行为的东西。

我第一次尝试了这段代码

代码语言:javascript
复制
#include <iostream>
#include <utility>
using namespace std ;

auto func() {
    int a = 0 ;

    auto increase = [ &a ]( int i = 1 ){ a += i ; } ;
    auto print = [ &a ](){ cout << a << '\n' ; } ;

    pair< decltype(increase), decltype(print) > 
    p = make_pair( increase, print ) ;
    return p ;
}

int main() {
    auto lambdas = func() ;

    auto increase = lambdas.first ;
    auto print = lambdas.second ;

    print() ;
    increase() ;
    print() ;
    increase( 123456 ) ;
    print() ;

    return 0;
}

输出与预期的相同

代码语言:javascript
复制
-1218965939
-1218965938
-1218842482

但是,在我将它添加到'func()‘之后

代码语言:javascript
复制
cout << typeid( decltype( print ) ).name() << '\n'
     << typeid( decltype( increase ) ).name() << '\n' ;

就像这一个

输出变成

代码语言:javascript
复制
Z4funcvEUlvE0_
Z4funcvEUliE_
0
1
123457

我没想到会发生。

更新

变量a应该是“死的”,因为它的生命周期已经结束了。

但我很好奇为什么typeiddecltype的代码测试似乎会使a复活呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-16 23:17:06

纯机会.

我怀疑您知道,您正在通过一个悬空引用打印未指定的值。

  • 在您的第一个示例中,悬空引用尝试从一个内存位置“读取”,该内存位置已经被重新用于其他东西。
  • 在您的第二个示例中,cout**s和/或** typeid**s已经影响了编译程序实现的血淋淋的内脏**,因此在非法打印a值时,a的内存位置恰好没有受到影响。

但是,试图进一步理顺这一点是没有意义的,下次运行该程序时,您可能会得到一个不同的结果。否则你的电脑就会爆炸。或者时间线可以被改变,以至于你从未出生过。不要试图解释UB的症状--只是避免它。

票数 2
EN

Stack Overflow用户

发布于 2016-05-16 23:12:38

您的程序的输出没有一个是“预期的”。

func()中的lambda通过引用捕获一个本地范围的变量,一旦func()返回,该变量就会超出作用域。

func()返回后,a不再存在,就像任何其他函数--本地作用域对象一样。因此,它们捕获的引用现在被引用到超出作用域并被销毁的对象,而引用值的任何使用都成为未定义的行为。

更糟糕的是,代码还通过无效引用来设置值.在传统的实现中,这将在堆栈的一些随机部分上乱写,这可能导致整个流程崩溃。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37264608

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档