hae*_*lix 6 c++ lambda temporary-objects forwarding-reference
下面的代码标准正确吗?(天马行空)
即 by-ref 捕获表示临时的转发引用,并在同一表达式中从函数返回结果 lambda 值。
当然,存储 lambda 以供以后使用会使它包含一个悬空引用,但我指的是main.
我的疑虑与这个 SO answer和潜在的这种语言缺陷有关。具体来说,有一个令人生畏的评论说“标准引用中的引用捕获生命周期规则捕获了变量,而不是数据及其范围” ——这似乎是说捕获的临时引用在我的代码中可能是无效的。
#include <stdlib.h>
#include <string.h>
#include <cassert>
template<typename F>
auto invoke(F&& f)
{
return f();
}
template<typename F>
auto wrap(F&& f)
{
return [&f]() {return f();}; // <- this by-ref capture here
}
int main()
{
int t = invoke(wrap(
[]() {return 17;}
));
assert(t == 17);
return t;
}
Run Code Online (Sandbox Code Playgroud)
您的代码中有 UB 用于相对较短的窗口。(注意:这是一个很奇怪的说法)。原始的 lambda 引用捕获规则规定引用仅在捕获的变量超出范围之前有效。
这可能会导致一种逐个引用的捕获,否则在 C++ 标准中是不可能的。(您可以获得的最接近的是对包含引用的单成员结构的引用)
理论上,您可以利用这一事实使 lambda 引用捕获基于堆栈帧;捕获当前堆栈帧,并且所有(几乎?)按引用参数都将在该堆栈帧的固定偏移量处。
由于大多数(所有?)ABI 将引用参数实现为引擎盖下的指针,这将导致函数参数的引用参数在 lambda 返回后悬空。
没有编译器利用这个事实。该优化从未使用过,只是尽可能地观察。“lambda 的引用捕获具有变量引用的生命周期”规则从未被任何编译器(或至少我听说过的任何编译器)利用。
当它被发现时,它在标准中被解析为缺陷解决方案,这意味着它追溯重新定义了c++11 的含义。
因此,虽然在历史上的c++11编译器下,这在技术上是 UB,但没有当前兼容的c++11编译器可以将其视为 UB,并且所有历史上的 C++11 编译器都以当前编译器的方式对待它。所以你很安全。