内部 lambda 中的悬空引用

14

我有一个内部Lambda,它使用了外部Lambda的一个引用变量,像这样:

int x=0;
auto outer=[&](){
   return [&](){
        x=5;
    };
};

auto inner= outer();
inner();
std::cout << x;

试过它。 它效果很好。 但是,我想确认这里没有悬挂的引用。 有吗?


8
在我看来,“the way I see it”是指向相同的“x”,而且由于你没有离开定义它的范围,所以它不是一个悬空引用。但是,我会让在SO上更有知识的人回答它。 - Algirdas Preidžius
3个回答

16

这里不存在悬空引用。内部 lambda 的引用不是对引用的引用(这种事情是不存在的);它是对 x 的引用 - 当然,x 没有超出其作用域。


4
所以,"references to references"这种东西不再存在了,从来没有真正存在过。但是在C++11中存在一个缺陷,将lambda捕获的引用变量的生命周期与其所捕获的引用变量的生命周期绑定,而不是与其引用的对象的生命周期绑定。甚至有优化相关的原因支持这么做(因为它允许[&] lambda捕获一个堆栈帧指针和可选的this指针,而不是其他任何东西)。 - Yakk - Adam Nevraumont
@Yakk 很有趣。谢谢你指出来。我很高兴我的假设是标准的意图 - eerorika
我现在相信我是错的。请阅读这里接受的答案 - Yakk - Adam Nevraumont
@Yakk 这个答案看起来和你说的很相似,只不过根据它的描述似乎是在 C++14 之后加入了破坏这段代码的措辞,希望在 C++17 发布之前能够修复。 - eerorika
是的,虽然在C++11和C++14中它很复杂但安全。然后在C++14之后添加了措辞,并在C++17之前进行了修复,这导致了问题。问题在于修复它的措辞不在引起问题的重新措辞的同一位置!因此我(以及链接中的原始答案)感到困惑,认为这是修复的C++14缺陷;实际上,这是在C++17最终确定之前修复的C++17缺陷。 - Yakk - Adam Nevraumont

7

如上所示,您正在块作用域内调用lambda,其中声明了x,并且没有悬空引用。

值得注意的是,内部匿名lambda直接从最外层块作用域捕获对x的引用,而不是来自外部lambda,因为它正在寻找声明。

如果您将(副本)lambda对象传递到该块作用域之外,那么可能会导致悬空引用。


4

如果你重写代码而不使用lambda表达式,那么我认为很明显没有悬空引用,只是对一个仍然在作用域内的变量x的引用:

class Inner {
    int& x;
  public:
    Inner(int &x) : x(x) {}
    void operator()(){
        x = 5;
    }
};

class Outer {
    int& x;
  public:
    Outer(int &x) : x(x) {}
    Inner operator()(){
        return {x};
    }
};

int main() {
    int x=0;
    auto outer = Outer{x};
    auto inner = outer();
    inner();
    std::cout << x;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接