2013-03-25 44 views
61

當我用[=]寫一個lambda時,這是否意味着我的所有局部變量都將被複制到創建的結構的成員中,或者我可以假設只有那些將在lambda中實際使用的變量?例如:是否[=]暗示所有局部變量將被複制?

void f() 
{ 
    vector<int> v(10000); 
    const int n = 5; 
    const int DivByNCnt = count_if(istream_iterator<int>(cin), istream_iterator<int>(), 
      [=](int i) 
      { 
      return i % n == 0; 
      }); 
} 

以下哪項是真的?

  • 兩個N和V將被複制
  • n將被複制,V不會
  • n將被複制,V可以或可以不依賴於implmenentation /優化設置複製。

假設參數的緣故,vector的拷貝構造函數有副作用。

+12

不知道任何關於C++ 11語義的知識,除了只有'n'被捕獲的任何東西,對於每一種其他語言的語義都具有一流的匿名函數和適當的關閉。 – Gian 2013-03-25 10:22:23

回答

63

不,這只是意味着來自環境範圍的所有局部變量都可用於lambda體內的查找。只有如果你指的是一個環境局部變量的名稱,那個變量將被捕獲,並且它將被值捕獲。

「捕獲任何東西」的縮寫=&只是語法糖,實質上是告訴編譯器「弄清楚我的意思」。


從5.1.2/11-12的正式參考:

如果λ-表達具有相關聯的捕獲默認及其化合物語句 ODR用途[。 ..]具有自動存儲持續時間的變量,並且odr使用的實體未被明確捕獲,則odr使用的實體被稱爲隱式捕獲

實體是如果明確或隱含捕獲,則捕獲

注意, 「捕獲默認」 是指[=][&]。重複一遍,指定capture-default不會捕獲任何東西;只有odr-使用變量。

+3

我毫不懷疑你是對的,但你有沒有參考? – 2013-03-25 10:24:20

+0

@AlexChamberlain:見5.1.2/11-12,關於「隱式和顯式捕獲」。它是*使用lambda體內的變量來進行捕獲。 – 2013-03-25 10:29:35

22

不! (謝天謝地)

你可以測試你的代碼來檢查你的編譯器是否真的做了它(或不)。例如gcc 4.8.0似乎是合規的。


至於什麼標準實際任務(向後工作):

§5.1.2/ 14的實體是通過複製捕獲,如果它被隱式的捕捉,默認爲=或者是否明確捕獲了不包含&的捕獲。對於通過複製捕獲的每個實體,在封閉類型中聲明一個未命名的非靜態數據成員。

$ 5.1.2/11如果lambda表達式具有關聯的捕獲默認值及其複合語句odr-使用(3.2)this或具有自動存儲持續時間的變量且未明確捕獲odr-used實體, 那麼odr-used實體據說被隱式捕獲;這些實體應該在lambda表達式的範圍內進行聲明。

§5.1.2/ 9其最小封閉範圍是塊範圍(3.3.3)的lambda表達式是局部lambda表達式;任何其他lambda表達式的lambda-introducer中都不應該有捕獲列表。本地lambda表達式的到達範圍是封閉範圍直到幷包括最內層封閉函數及其參數的集合。 [注意:這個範圍包括任何介入的lambda表達式。 - 注意]

+1

MSVC 10.0不會複製v,但我想知道是否有保證v不會被複制! – 2013-03-25 10:27:58

+0

@ArmenTsirunyan:我添加了標準的相應引用。根據§5.1.2/ 14,只有被捕獲的成員應該被關閉。 – 2013-03-25 10:42:01

相關問題