C++ Lambda按引用捕获:成员变量何时及为何发生变更?
C++ Lambda按引用捕获的变量变更问题解析
先看你提供的示例代码:
#include <iostream> #include <functional> using namespace std; function<int(int)> func1( int y ) { return [&]( int argument ) { return argument + y; }; } function<int(int)> func2( int y ) { class Lambda { public: Lambda( int& data ) : m_data( data ) { cout << "ctor: " << m_data << endl; } int operator () ( int argument ) { cout << "data lambda: " << m_data << endl; // why and when does m_data change? cout << "argument lambda: " << argument << endl; return m_data + argument; } const int& m_data; }; return Lambda( y ); } int main() { // rewritten lambda auto lambda1 = func1( 1 ); auto result1 = lambda1( 10 ); cout << "lambda2( 10 ) = " << result1 << endl; // C++ lambda auto lambda2 = func2( 1 ); auto result2 = lambda2( 10 ); cout << "lambda2( 10 ) = " << result2 << endl; }
运行输出:
lambda2( 10 ) = 20 ctor: 1 data lambda: 10 argument lambda: 10 lambda2( 10 ) = 20
核心问题解析
你疑惑的m_data从1变为10,本质是悬垂引用引发的未定义行为,具体原因如下:
- 局部变量生命周期终止:func2的参数
y是函数栈上的局部变量,当func2执行完成返回Lambda对象后,y的生命周期就结束了,对应的栈内存会被系统标记为可复用。而Lambda的成员m_data是一个引用,绑定的正是这个已经销毁的y。 - 栈内存被复用覆盖:当你在main函数中调用
lambda2(10)时,程序需要将参数10压入栈中,此时之前存放y的那块栈内存刚好被这个参数值覆盖,所以访问m_data时就读到了10。 - func1的情况完全一致:func1返回的lambda同样按引用捕获了局部变量
y,导致悬垂引用,执行lambda1(10)时的结果也是栈内存复用的巧合,并非预期行为。
正确做法
如果需要让lambda在函数外部正常工作,要么按值捕获局部变量(把[&]改成[=],或者显式[y]),要么确保被引用的变量生命周期长于lambda(比如使用全局变量、动态分配的内存,或者让变量存在于lambda的作用域之外)。
内容的提问来源于stack exchange,提问作者nonsensation
相关产品推荐
相关产品推荐

