2017-05-17 40 views
5

今天我在C++ 11 lambda中遇到了一個非常不直觀的行爲(至少對我來說)。有問題的代碼如下:返回一個lambda捕獲一個局部變量

#include <stdio.h> 

auto sum(int x) { 
    return [&x](int y) { 
     return x + y; 
    }; 
} 

int main() { 
    int a = sum(2)(3); 
    printf("%d\n",a); 
} 

而不是打印5,這種打印亂碼。實際上,至少在我的GCC版本中,如果打開-O2優化標誌,它實際上會打印5.由於輸出取決於編譯器的優化級別,因此它是未定義的行爲。過了一段時間,我想我明白髮生了什麼事。

當函數sum被調用時,與參數x相對應的堆棧變量被設置爲2,然後函數sum返回,並且該堆棧變量可能被編譯器需要放置的任何東西覆蓋以執行下面的代碼,並且在lambda最終得到執行時,x不再存在的地方保存爲2,程序將3加到任意整數。

是否有任何優雅的方式來做C++中的currying保證變量被正確捕獲?

+4

按值「[=]」捕獲。 – Galik

+0

謝謝!這比我想象的要簡單。 –

+2

僅供讀者閱讀,這是C++ 14,而不是C++ 11。在C++ 14中添加了函數返回值的類型推導。 – cdhowie

回答

8

int x的使用壽命有限。自動存儲變量的引用(你稱之爲「堆棧」)只在變量的生命週期內有效。在這種情況下,直到變量存在的棧幀(範圍)結束或函數參數的函數結束。

[&]通過引用捕獲任何提及的(「本地」)變量,除了this(如果使用或隱含地使用該值,則被捕獲值)。 [=]通過值捕獲任何提到的變量。 [x]將顯式地捕獲x,並明確引用[&x]。在C++ 17中,[*this]也適用。

還有[x=std::move(x)][blah=expression]

一般來說,如果lambda將超過當前範圍,請不要使用[&]:明確說明您捕獲的內容。

+0

感謝您的精心解答。我查找的大部分答案都涉及到C++的currying,但有很多模板代碼是我無法理解的,所以我只是開始嘗試一些東西。現在我更瞭解我在做什麼。 –