鉴于以下计划:
#include <iostream>
#include <memory>
using namespace std;
int main() {
std::shared_ptr<int> i(new int(42));
cout << i.use_count() << endl;
auto fn = [=](){i; cout << 42 << endl;};
cout << i.use_count() << endl;
return 0;
}
编译器何时决定捕获哪些对象?
shared_ptr i
从未在lambda表达式中使用。因此,在正常函数中,我会假设优化器将删除此nop语句
但如果删除它,编译器可能会认为不需要捕获i
。
因此,使用gcc,该程序将始终生成1,2作为输出 但这是否由标准保证?
答案 0 :(得分:2)
如果我们转到lambda function上的cppreference页面,他们会有以下解释:
[=]按值
捕获lambda体中提到的所有自动变量
并进一步说:
捕获列表是以逗号分隔的零个或多个捕获列表,可选择以capture-default开头。唯一的捕获默认值是&amp; (通过引用隐式捕获odr使用的自动变量)和=(隐式捕获odr使用的自动变量,按值计算)。
odr-used的参考部分说:
如果变量的名称显示为可能已评估的表达式,则该变量使用odr,除非以下所有内容都是 真:
- 将lvalue-to-rvalue转换应用于exression会产生一个不会调用非平凡函数的常量表达式
- 表达式是丢弃值表达式或左值到右值转换
例外情况不适用于i
,因此会捕获i
。
哪个与draft C++11 standard部分5.1.2
Lambda表达式段 11 一致,其中包含:
如果lambda表达式具有关联的capture-default及其 复合语句odr-uses(3.2)this或变量with automatic 存储持续时间和odr使用的实体未明确捕获, 然后,据说隐含地捕获了使用过的实体;这样 实体应在lambda的范围内声明 表达
答案 1 :(得分:2)
默认捕获[=]
,如果它在lambda中 odr-used ,则捕获任何局部变量。 odr-used 的定义是:
名称显示为可能已评估的表达式的变量是 odr-used ,除非它是满足出现在常量表达式中的要求的对象,并且lvalue-to-rvalue转换是立即的应用
这里,i
是一个评估表达式,并且不是常数;所以它是odr-used
因此被捕获;是否评估表达式有任何影响。
但这是否由标准保证?
tl;是的。