在 C 11 Lambda 中捕获引用
在 C 中,lambda 表达式可以从其封闭范围捕获变量。然而,捕获的方法决定了变量是通过引用还是通过值访问。考虑以下代码:
<code class="cpp">#include <functional> #include <iostream> std::function<void()> make_function(int& x) { return [&]{ std::cout << x << std::endl; }; } int main() { int i = 3; auto f = make_function(i); i = 5; f(); }</code>
此代码使用 [&] 语法通过引用捕获变量 x。问题是这个程序是否保证在不调用未定义行为的情况下输出 5。
答案:是
代码保证正确工作。在检查底层标准措辞之前,重要的是要注意此代码的功能符合 C 委员会的预期。然而,C 11 标准的最初措辞在这一问题上并不清楚,导致 CWG 问题 2011 被提出来提供澄清。这个问题正在C标准的持续开发中得到解决。
标准解释
根据C标准的[expr.prim.lambda]/17,只有引用复制捕获的实体的 id 表达式才会转换为 lambda 闭包类型的成员访问。引用通过引用捕获的实体的 id 表达式将被保留,并继续表示它们在封闭范围中表示的相同实体。
在上面的代码中,捕获的实体是 make_function 函数的参数 x ,落在 lambda 的可达范围内。因此,lambda 表达式中的引用 x 引用了在 main 函数中声明的原始变量。
在 make_function 函数返回后,在 x 的生命周期之外引用 x 最初可能会出现问题。但是,在有限的情况下,可以在引用的生命周期之外对其进行引用。一般来说,引用要么在作用域中声明,要么是类成员,在这种情况下,类本身必须在其生命周期内。
因此,标准没有明确禁止在其生命周期之外使用引用。此漏洞允许支持在 lambda 表达式中通过引用捕获引用。
CWG 2012 期问题和未来澄清
提出 CWG 2012 期问题是为了解决监督问题在某些情况下,引用可以在其生命周期之外被引用。此问题的解决无意中影响了通过引用引用捕获 lambda 的规范。不过,预计此回归将在 C 17 发布之前修复。
以上是C 11 Lambda 能否在不调用未定义行为的情况下捕获引用?的详细内容。更多信息请关注PHP中文网其他相关文章!