我试图弄清楚lambda如何在C ++中运行。
发生了一件奇怪的事。很奇怪,我不知道如何正确描述它。我尝试使用谷歌搜索几个关键字,但没有找到任何提及行为的内容。
我首先尝试this code。
#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;
}
输出符合预期
-1218965939
-1218965938
-1218842482
然而,在我将其添加到&#39; func()&#39;之后
cout << typeid( decltype( print ) ).name() << '\n'
<< typeid( decltype( increase ) ).name() << '\n' ;
喜欢this one
输出成为
Z4funcvEUlvE0_
Z4funcvEUliE_
0
1
123457
我没想到会发生。
[更新]
变量a
应该是&#34;死&#34;因为它的生命周期已经结束。
但我很好奇为什么代码考试typeid
和decltype
导致a
似乎复活了?
答案 0 :(得分:4)
您通过引用绑定到a
。但这是一个存储在堆栈中的局部变量。一旦函数完成执行,它就是未定义的行为。
与返回指向a
的指针然后从调用者开始使用它的情况相同。
答案 1 :(得分:3)
您的计划的所有输出都不是“按预期”。
func()
中的lambdas通过引用捕获一个本地范围的变量,一旦func()
返回就会超出范围。
func()
返回后,a
不再存在,就像任何其他函数本地范围对象一样。因此,他们捕获的引用现在被引用到超出范围并被销毁的对象,并且引用值的任何使用都变为未定义的行为。
更糟糕的是,代码还通过不再有效的引用设置值。在传统的实现中,这会乱写堆栈的一些随机部分,这可能导致整个过程崩溃。
答案 2 :(得分:2)
纯粹的机会。
我怀疑你知道,你是通过悬空参考打印未指定的值。
在您的第一个示例中,悬空引用尝试从已经重新用于其他内容的内存位置“读取”。
在您的第二个示例中, cout
和/或typeid
已经影响了编译程序实现的血腥胆量,使得内存a
的位置恰好在您非法打印其价值时不受影响。
但是,在尝试进一步理解这一点时,没有意义,并且下次运行程序时可能会得到不同的结果。或者您的计算机可能爆炸。或者可以改变时间表,使你从未出生过。 不要试图解释UB的症状 - 只要避免它。