C++ lambda:好的参考与坏的参考
C++ lambda: good reference vs. bad reference
我正在观看 CppCon 2015 视频:为什么按值捕获是好的,而按引用捕获是不好的。
Arthur 解释了,但我不明白...Arthur 说一个错误的引用指的是一个局部变量然后退出,但是退出后堆栈应该清理并且局部变量消失了,所以有什么问题?
BAD_increment_by
returns 一个包含对 y
的引用的闭包,但是当该函数 returns 时 y
超出范围,所以它包含一个悬空引用。任何调用该闭包的尝试都是未定义的行为。
因为同样的原因,它很糟糕:
int& BAD_copy(int x) { return x; }
不好。
我想尝试用另一种方式解释@Barry 的回答。
让我们写下里面发生的事情BAD_increment_by
。
- 有一个局部变量,
y
。
- 通过引用捕获 lambda
y
。这将创建一个名为 y
的引用。好吧,他们恰好有相同的名字,这令人困惑......让我们称第一个为"value y
",第二个为"reference y
"。
- lambda 的主体使用引用
y
。
- lambda 由
BAD_increment_by
返回。
从BAD_increment_by
回来后,
- 值
y
不再存在。
- 引用
y
仍然指向值 y
...
- 等等!值
y
不存在!参考 y
指向不存在的内容!
当有人调用 lambda 时,
- 已阅读参考
y
。
- 由于引用
y
是一个引用,我们被重定向到值 y
。
- 呃……是真的值
y
还是我的幻觉?
结论是:调用lambda时,使用了悬空引用。行为未定义。
您可以将 lambda 视为 shorthand 对应 class 并定义了 operator()
,因此可以将其视为函数。
auto BAD_increment_by(int y)
{
return [&](int x){return x+y;};
}
以下内容可被视为简写:
struct BadClosure
{
int& y;
BadClosure(int& y) // y is the only variable in scope
: y(y) // So the `&` only captures 'y'
{}
auto operator()(int x){return x+y;}
};
auto BAD_increment_by(int y)
{
return BadClosure(y);
}
所以如果我使用上面的:
int main()
{
// This object now has a reference to
// parameter 'y' from the function `BAD_increment_by()`
//
// But this function has exited.
// So the reference held by this object is no longer
// valid (ie it is a dangling reference).
auto addTwo = BAD_increment_by(2);
// Now use it
// Internally this access the member y
// which is a reference to the parameter 'y'
// from a function that is no longer executing.
std::cout << addTwo(5) << "\n";
}
我正在观看 CppCon 2015 视频:为什么按值捕获是好的,而按引用捕获是不好的。
Arthur 解释了,但我不明白...Arthur 说一个错误的引用指的是一个局部变量然后退出,但是退出后堆栈应该清理并且局部变量消失了,所以有什么问题?
BAD_increment_by
returns 一个包含对 y
的引用的闭包,但是当该函数 returns 时 y
超出范围,所以它包含一个悬空引用。任何调用该闭包的尝试都是未定义的行为。
因为同样的原因,它很糟糕:
int& BAD_copy(int x) { return x; }
不好。
我想尝试用另一种方式解释@Barry 的回答。
让我们写下里面发生的事情BAD_increment_by
。
- 有一个局部变量,
y
。 - 通过引用捕获 lambda
y
。这将创建一个名为y
的引用。好吧,他们恰好有相同的名字,这令人困惑......让我们称第一个为"valuey
",第二个为"referencey
"。 - lambda 的主体使用引用
y
。 - lambda 由
BAD_increment_by
返回。
从BAD_increment_by
回来后,
- 值
y
不再存在。 - 引用
y
仍然指向值y
... - 等等!值
y
不存在!参考y
指向不存在的内容!
当有人调用 lambda 时,
- 已阅读参考
y
。 - 由于引用
y
是一个引用,我们被重定向到值y
。 - 呃……是真的值
y
还是我的幻觉?
结论是:调用lambda时,使用了悬空引用。行为未定义。
您可以将 lambda 视为 shorthand 对应 class 并定义了 operator()
,因此可以将其视为函数。
auto BAD_increment_by(int y)
{
return [&](int x){return x+y;};
}
以下内容可被视为简写:
struct BadClosure
{
int& y;
BadClosure(int& y) // y is the only variable in scope
: y(y) // So the `&` only captures 'y'
{}
auto operator()(int x){return x+y;}
};
auto BAD_increment_by(int y)
{
return BadClosure(y);
}
所以如果我使用上面的:
int main()
{
// This object now has a reference to
// parameter 'y' from the function `BAD_increment_by()`
//
// But this function has exited.
// So the reference held by this object is no longer
// valid (ie it is a dangling reference).
auto addTwo = BAD_increment_by(2);
// Now use it
// Internally this access the member y
// which is a reference to the parameter 'y'
// from a function that is no longer executing.
std::cout << addTwo(5) << "\n";
}