C++ Lambda按引用捕获引用变量

C++ Lambda按引用捕获引用变量,c++,c++11,lambda,C++,C++11,Lambda,对于lambda,我想通过引用捕获一些已经在外部范围内的东西。假设引用值超过lambda,但不超过创建lamdba的范围 如果lambda按值捕获引用变量,则将复制引用对象。我想避免这本书 但是如果我通过引用捕获引用变量会发生什么呢?如果原始引用变量在执行lambda之前超出作用域,该怎么办?这安全吗?换句话说:引用后面的对象是被引用的还是lambda中引用的引用变量 auto f() { const auto & myRef = g(); return [&]{

对于lambda,我想通过引用捕获一些已经在外部范围内的东西。假设引用值超过lambda,但不超过创建lamdba的范围

如果lambda按值捕获引用变量,则将复制引用对象。我想避免这本书

但是如果我通过引用捕获引用变量会发生什么呢?如果原始引用变量在执行lambda之前超出作用域,该怎么办?这安全吗?换句话说:引用后面的对象是被引用的还是lambda中引用的引用变量

auto f() {
    const auto & myRef = g();
    return [&]{ myRef.doSomething(); };
}

f()();  // Safe?
是的,通过引用捕获对象的关键问题是被引用对象的生存期,而不是用于获取它的任何中间引用的生存期。您可以将引用视为别名,而不是实际变量。(在类型系统中,引用的处理方式与常规变量不同。)引用为原始对象添加别名,并且独立于用于为对象添加别名的其他别名(不同于它们为同一对象添加别名的事实)

====编辑======

根据给出的答案(由dyp指出),这似乎并不完全清楚。在语言的其余部分,“引用引用”的概念没有任何意义,从引用创建的引用成为该引用的对等引用,但显然,该标准对这种情况有点模糊,lambda捕获的引用在某种意义上可能是次要的,取决于从中捕获它们的堆栈帧。(SO答案引用的明确措辞特别指出了引用的实体,这从表面上表明只要原始对象存在,这种用法是安全的,但绑定机制可能暗示捕获链是重要的。)

我希望这在C++14/17中得到澄清,我更希望得到澄清,以保证这种用法的合法性。特别是,我认为C++14/17通过表达式捕获变量的能力会使通过堆栈帧指针捕获范围变得更加困难,最明智的捕获机制通常是单独捕获特定实体。(如果通过引用捕获实际的本地对象,则可能允许堆栈帧捕获,因为如果在任何情况下在范围外调用lambda,这将导致UB。)


在我们得到一些澄清之前,这可能是不可移植的。

谢谢,我99%确定,但希望得到一些确认。通过引用捕获不(一定)创建引用。根据雅克对我的问题的评论,你的答案是不正确的:(除了本例中的“引用实体”外,它是函数local reference
myRef
,不是对象。lambda中没有引用(不一定),因此没有引用。“通过引用捕获”是一个相当历史性的术语,因为早期版本的lambdas为闭包类型指定了引用类型的数据成员。这在C++11之前已被删除,现在只有对实体的访问在lambda内部指定(或者更确切地说,没有到另一个实体的转换,因此从外部范围访问原始实体).这里的实体是一个声明为引用的变量。我相信不是。除了理论之外,还有一种有效的实现方法用于存储堆栈深度,并在lambda正文中对此进行硬编码偏移。这将把您的状态减少到一个指针,而不是每个变量一个指针。至于这是一个合法的实现,我想我在其他地方看到了这一点。哦,请注意引用生命周期延长的危险。作为一种解决方案,通过值捕获引用包装器?Dup?@dyp假设g返回对长期对象的引用。如OP中所述。另一种解决方法:
auto myRef=std::cref(g());return[=]{myRef.get().doSomething();}
@leems
[&myRef=myRef]
应该可以。这会在闭包中创建一个引用数据成员。
[myRef=*&myRef]
执行复制,就像
[myRef=myRef]
一样。