【问题标题】:Why does lambda capture by reference is still working with dangling references?为什么 lambda 通过引用捕获仍在使用悬空引用?
【发布时间】:2020-08-11 10:34:06
【问题描述】:

令我惊讶的是,下面的 C++ 程序:

#include <iostream>
#include <functional>


int main() {
    std::function<void(void)> f;
    {
        int x = 1;
        f = [&x]() { std::cout << x; };
    }
    //std::cout << x;  // error: use of undeclared identifier 'x'
    f();               // no error!
    return 0;
}

输出:

1

我希望得到的输出与取消注释注释行时得到的输出相同:

error: use of undeclared identifier 'x'

因为 lambda f 捕获了自动变量 x 通过引用(不是 通过值)并且 x 在调用点不在上下文中f()(所以 x 中的 f body 是一个悬空引用)。

为什么通过引用捕获的 lambda 仍然适用于悬空引用?

【问题讨论】:

  • 这是未定义的行为,你很幸运得到了你所做的输出,而且它似乎正在工作,不同的编译器/不同的优化或编译器标志可能会破坏它。
  • 为什么在没有任何 lambdas 的情况下悬空引用起作用?

标签: c++ lambda scope reference name-binding


【解决方案1】:

为什么通过引用捕获的 lambda 仍然适用于悬空引用?

这是未定义的行为,因此可以有任何理由说明它的工作方式。如果你编译代码:

在这里试试:https://godbolt.org/z/5dd5sM

clang++ -O3 -fsanitize=address

您将立即获得:

ERROR: AddressSanitizer: stack-use-after-scope on address ....
READ of size 4...

【讨论】:

    【解决方案2】:

    它不工作。这只是一个巧合,它显示为 1。只是在调用 lambda 时驻留在捕获的地址中的东西保存了可以解释为值为 1 的 int 类型的值。

    lambda 的生命周期大于变量的生命周期。变量 x 在右大括号处被销毁,但 lambda 仍然持有对它的引用。任何访问该引用的尝试都会导致未定义的行为。

    在 lambda 声明中,您告诉 什么 要捕获。使用声明它的地方的当前范围。在调用 lambda 时,您告诉 when 进行捕获。这就是为什么它与您问题中的参考文献相比可以编译的原因。但您有责任提供所用变量的正确生命周期。

    【讨论】:

      猜你喜欢
      • 2019-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多