在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()
(以便第一次调用工作)或程序启动时?
答案 0 :(得分:13)
当控制流首次到达其声明时,静态函数范围变量“懒洋洋地”初始化。这意味着通过引用捕获确实绑定到当前堆栈上的foo
,并且当调用终止时,该绑定变为悬空。
不要试图过多地帮助编译器;使lambda
static
看起来像微优化,副作用非常严重。实际上创建一个闭包对象几乎没有任何开销,编译器可以轻松地内联它,无论它是否static
。
更不用说即使使用您的方法,您也无法保存创建std::function
对象。 lambda表达式的类型是未命名的闭包对象, not std::function
。因此,即使lambda
为static
,也会在每次调用中创建std::function
对象(除非整个内容都被内联)。
答案 1 :(得分:0)
这不适用于
doSomething()
的多次调用,但机制尚不清楚。
这是因为在堆栈上分配了foo
。 foo
的确切地址取决于导致调用doSomething
的调用堆栈。换句话说,函数调用之间foo
的地址可能不同,除非调用堆栈完全相同。