const-static auto lambda与引用捕获一起使用



在C++11函数中使用一些本地lambda对象时,我很想将它们声明为const static auto lambda = ...,只是为了让编译器知道只需要一个std::function对象(并可能优化调用和/或内联它),但我意识到在这种情况下通过引用捕获本地值会导致奇怪的行为。

考虑以下代码:

void process(const Data& data, const std::function<void(DataElement&>& lambda) {
  ...
}
void SomeClass::doSomething()
{
  int foo = 0;
  const static auto lambda = [&foo] () { .... ++foo; .... }
  process(data, lambda);
}

这不适用于多次调用doSomething(),但机制尚不清楚。

  • foo是否在第一次调用时绑定,然后保持绑定到堆栈地址,该地址在连续调用时变为无效
  • 在这种情况下,我是不是被迫放弃static

标准中对这种行为的规定在哪里?考虑到它是一个static变量,它是在哪里构造的?在doSomething()的第一次调用时懒散(这样第一次调用就可以工作了)还是在程序启动时懒散?

当控制流第一次到达其声明时,静态函数作用域变量被"延迟"初始化。这意味着通过引用捕获确实绑定到当前堆栈上的foo,并且当调用终止时,该绑定变为悬空。

不要试图过多地帮助编译器;使lambda static看起来像是一个微观优化,具有非常糟糕的副作用。实际上创建闭包对象几乎不涉及任何开销,而且无论它是否为static,编译器都可以轻松地内联它。

更不用说,即使使用您的方法,也不会节省创建std::function对象的成本。lambda表达式的类型是未命名的闭包对象,而不是std::function。因此,即使lambdastaticstd::function对象也会在每次调用中创建(除非整个调用都是内联的)。

这不适用于多次调用doSomething(),但机制尚不清楚。

这是因为foo是在堆栈上分配的。foo的确切地址取决于导致调用doSomething的调用堆栈。换句话说,除非调用堆栈完全相同,否则函数调用之间foo的地址可能不同。

最新更新