c ++ 11对lambda初始化的惩罚

时间:2016-05-12 13:57:21

标签: c++ performance c++11 lambda

给定的

class C;
void do_something_else( std::function< void ( C &)> );


class A1{
   void do_something(C &);

   void test(){ 
      int i;
      for (i=0; i<100; i++)
          do_something_else([this]( C & C_){ this->do_something(C_); } );
   }
};

class A2{
   std::function< void ( C &)> lambda;
   void do_something(C &);

   A2():lambda([this]( C & C_){ this->do_something(C_) ;}){}

   void test(){ 
      int i;
      for (i=0; i<100; i++)
          do_something_else(lambda);
   }  
};

A1::test()A2::test()

之间是否存在性能差异?

1 个答案:

答案 0 :(得分:2)

std::function被要求使用小对象优化来在自己内部存储小的invokable,而无需在免费商店上分配内存。

你的lambda很小,所以在一个典型的基于类型擦除的实现中从它创建一个std::function涉及设置虚拟函数表指针的粗略等价物,并在位于内部的内存缓冲区中执行放置构造std::function本身。

lambda的大小是一个指针(this)。虚函数表将编写另一个常量(或者可能是一些常量指针,具体取决于实现是否以std::function内的vtable“内联”以大小为代价来换取位置。

任何非平凡的操作都会压低创建如此小的std::function的成本。

此外,您使用std::function< void ( C &)>按值:这意味着第一个展示位置构建std::function,而第二个副本 - 从现有std::function构建它。复制构造可能涉及使用虚拟表来复制状态,但优化的std::function可以保留“平凡可复制状态”的标志以避免该间接(以分支为代价)。

接下来,编译器可能能够通过内联类实例并将分配展开到内存来解码您对std::function所执行的操作。它甚至可能完全消除std::function的存在。编译器在这方面继续变得更好。

最后,您注意到您在微基准测试中看到了4%的性能差异。这是(弱)证据表明没有显着差异,因为微基准环境和“真实”环境之间的差异将会超过这么小的差异。

使用以使代码更清晰的方式。