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

  1. 有一个局部变量,y
  2. 通过引用捕获 lambda y。这将创建一个名为 y 的引用。好吧,他们恰好有相同的名字,这令人困惑......让我们称第一个为"value y",第二个为"reference y"。
  3. lambda 的主体使用引用 y
  4. lambda 由 BAD_increment_by 返回。

BAD_increment_by回来后,

  1. y 不再存在。
  2. 引用 y 仍然指向值 y...
  3. 等等!值 y 不存在!参考 y 指向不存在的内容!

当有人调用 lambda 时,

  1. 已阅读参考 y
  2. 由于引用 y 是一个引用,我们被重定向到值 y
  3. 呃……是真的值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";
}