[英]C++ lambda by-value capture semantics and allowed optimizations
当只有隐式捕获对象的某些数据成员被仿函数实际使用时,编译器允许从按值默认捕获中省略什么? 例如,
struct A {
// some members we care about:
char x;
int y;
// some huge amount of state we do not:
std::array<bool, 200000> z;
int foo() const { return y + 1 }
};
void bar() {
A a;
// must the entirety of a be copy captured, or is the compiler allowed to pick/prune?
auto l1 = [=](){ std::cout << a.x << ", " << a.y << std::endl; };
// ...
}
同样,如果早期评估允许省略更广泛的捕获?
void baz(int i) {
A a2;
a2.y = i;
// capture fundamentally only needs 1 int, not all of an A instance.
auto l2 = [=](){ std::cout << a.foo() << std::endl; }
}
至少在某些情况下,对元素进行部分与完整的副本捕获应该没有超出lambda大小的可见外部效果,但我不知道规范中的哪个位置寻找可以允许的优化的答案。
我认为,原则上,允许编译器以一种仅在as-if规则下捕获已使用成员的副本的方式对其进行优化。 [expr.prim.lambda]§2的相关部分:
[...]实现可以定义闭包类型与下面描述的不同,前提是这不会改变程序的可观察行为,只需更改:
- 封闭类型的大小和/或对齐方式,
- 封闭类型是否可以轻易复制,或者
- 闭包类型是否为标准布局类。
但是,在检查闭包类型的sizeof()
的快速测试中,主要编译器(clang,gcc,msvc)似乎都没有以这种方式优化闭包类型本身。
但应该注意的是,只有在实际存储从某个lambda表达式获取的对象时(例如在std::function
),这才真正成为一个问题。 通常情况下,lambda表达式的结果将仅用作某个函数模板的参数,然后丢弃。 在这种情况下,所有内容最终都被内联,优化器应该(并且在我的测试中做)只丢弃为从未引用的数据复制而生成的代码...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.