[英]C++ lambda by-value capture semantics and allowed optimizations
What is the compiler allowed to omit from by-value default captures, when only some data members of an implicitly captured object are actually used by the functor? 当只有隐式捕获对象的某些数据成员被仿函数实际使用时,编译器允许从按值默认捕获中省略什么? Eg, 例如,
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; };
// ...
}
Similarly, when if ever is early evaluation allowed to omit broader captures? 同样,如果早期评估允许省略更广泛的捕获?
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; }
}
There are at least some situations where making a partial vs. complete copy capture of an element should have no visible external effects beyond lambda size, but I do not know where in the spec to look for the answer to what optimizations are allowable. 至少在某些情况下,对元素进行部分与完整的副本捕获应该没有超出lambda大小的可见外部效果,但我不知道规范中的哪个位置寻找可以允许的优化的答案。
I think that, in principle, a compiler would be allowed to optimize this in a way that would capture only a copy of the used member under the as-if rule. 我认为,原则上,允许编译器以一种仅在as-if规则下捕获已使用成员的副本的方式对其进行优化。 The relevant part of [expr.prim.lambda] §2 : [expr.prim.lambda]§2的相关部分:
[…] An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing: [...]实现可以定义闭包类型与下面描述的不同,前提是这不会改变程序的可观察行为,只需更改:
- the size and/or alignment of the closure type, 封闭类型的大小和/或对齐方式,
- whether the closure type is trivially copyable, or 封闭类型是否可以轻易复制,或者
- whether the closure type is a standard-layout class. 闭包类型是否为标准布局类。
However, in a quick test checking for sizeof()
of the closure type, none of the major compilers (clang, gcc, msvc) seemed to optimize the closure type itself in such ways. 但是,在检查闭包类型的sizeof()
的快速测试中,主要编译器(clang,gcc,msvc)似乎都没有以这种方式优化闭包类型本身。
It should be noted, though, that this only really becomes an issue as soon as you actually store the object obtained from a lambda expression somewhere (eg in an std::function
). 但应该注意的是,只有在实际存储从某个lambda表达式获取的对象时(例如在std::function
),这才真正成为一个问题。 More often than not, the result of a lambda expression will simply be used as an argument to some function template and then thrown away. 通常情况下,lambda表达式的结果将仅用作某个函数模板的参数,然后丢弃。 In such a case, where everything ends up being inlined, the optimizer should (and did in my tests) just throw away code generated for copying around data that is never referenced… 在这种情况下,所有内容最终都被内联,优化器应该(并且在我的测试中做)只丢弃为从未引用的数据复制而生成的代码...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.