C ++ lambda按值捕获语义和允许的优化

时间:2018-07-25 02:10:17

标签: c++ c++11 lambda

当函子实际上仅使用隐式捕获对象的某些数据成员时,编译器允许从按值缺省捕获中忽略什么?例如,

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大小而没有可见的外部影响,但是我不知道在规范中何处寻找允许哪些优化的答案

1 个答案:

答案 0 :(得分:3)

我认为,原则上,将允许编译器以某种方式优化此方式,该方式将仅在as-if规则下捕获使用的成员的副本。 [expr.prim.lambda] §2的相关部分:

  

[…]实现可以定义闭包类型,其方式与以下描述不同,前提是该闭包类型除了更改以外不会改变程序的可观察行为:

     
      
  • 闭合类型的大小和/或对齐方式
  •   
  • 关闭类型是否可以简单复制,或者
  •   
  • 闭合类型是否为标准布局类。
  •   

但是,在对闭包类型的sizeof()进行快速测试时,似乎没有一个主要的编译器(clang,gcc,msvc)以这种方式优化闭包类型。

不过,应该注意的是,只有将从lambda表达式获得的对象实际存储在某个地方(例如,放在std::function中)后,这才真正成为问题。通常,lambda表达式的结果将仅用作某些函数模板的参数,然后被丢弃。在这种情况下,所有内容最终都被内联,优化器应该(并且在我的测试中这样做)只是丢弃生成的代码,用于围绕从未引用的数据进行复制……