简体   繁体   English

C ++ lambda by-value捕获语义和允许的优化

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM