2015-11-17 115 views
4

考慮一下:爲什麼我們需要捕獲lambda參考的參考?

class TestLambda { 
public: 
    std::vector<char> data; 
}; 

void test_lambda(TestLambda& obj) { 
    [=]() mutable { 
     obj.data.push_back(0x01); 
    }(); 
} 

int main() { 
    TestLambda tst; 
    tst.data.push_back(0x99); 
    test_lambda(tst); 

    // tst.data is unchanged at this point 

    return 0; 
} 

調用test_lambda我所期待的是看到在tst.data變更後,但情況並非如此。要查看更改,我必須再次創建lambda傳遞參考obj,即。 [&obj]()

爲什麼我們需要這個?我的意思是,又是一個參考?

obj已經是參考。然後,lambda通過複製它來捕獲obj。那麼,obj以內lambda本身是不是一個參考?爲什麼?

有人可以解釋我嗎?謝謝。

+0

引用是一個別名,所以它只是另一個左值。在幾乎所有情況下,它的行爲與它所引用的變量沒有區別。製作原件或別名的副本,其副本仍然是其副本。 – sp2danny

回答

5

當在分配的右側使用時,引用就像「正常」變量一樣工作。無論何時定義的值拉姆達捕獲,拉姆達擁有外部變量的副本,彷彿拉姆達開始與這些行:

auto my_inner_variable = my_outer_reference; 
auto my_inner_other_variable = my_outer_other_variable; 

如果你想提到的「保持」的引用,你必須通過引用捕獲它,從而告訴編譯器發出這樣的代碼:

auto& my_inner_variable = my_outer_reference; 
auto& my_inner_other_variable = my_outer_other_variable; // if we instructed to capture everything by reference 
3

根據該標準草案§5.1.2/ P15 Lambda表達式[expr.prim.lambda]重點礦山):

的實體是通過拷貝捕獲如果它是隱式捕獲並且捕獲默認= =或者如果它明確地被捕獲 ,其形式不是&標識符或&標識符初始化器。 對於通過複製捕獲的每個實體,在封閉類型中聲明的未命名的非靜態數據成員爲 。這些成員 的聲明順序未指定。 這種數據成員的類型是對應捕獲實體的類型,如果該實體不是對象的引用,或者是其他引用類型的引用。 [注意:如果捕獲的 實體是對函數的引用,則對應的數據成員也是 也是對函數的引用。 - 結束註釋]匿名 聯盟的成員不得通過複製獲取。

因此,在:

void test_lambda(TestLambda& obj) { 
    [=]() mutable { 
     obj.data.push_back(0x01); 
    }(); 
} 

obj被複制捕獲,因此你理所當然所描述的結果。換句話說,這是標準規定的[=]捕獲默認行爲。

+0

如何「隱式」捕獲obj? [](){}給我「未捕獲」的錯誤。 +1。 –

+0

我認爲OP明白'[=]'的含義。我認爲這個問題是關於捕獲實體的類型:爲什麼捕獲的參考文件會複製一份。捕獲可以被演示爲:'auto objCopy = obj;'在lambda中,它應該是'TestLambda objCopy = obj;'還是'TestLambda&objCopy = obj;'? @Lodo的回答解決了這個問題,即使不完全清楚 –

+0

@AndyT正確。我的知識缺乏是在做TestLambda時發生了什麼objCopy = obj;現在我明白了爲什麼它不能作爲參考。 –

0

你的功能test_lambda包含嵌套lambda函數。在test_lambda內部,參考obj主要參考tst。然後你調用一個匿名的lambda函數,通過值來捕獲。lambda函數obj內部是obj的副本,位於test_lambda內部。爲什麼不乾脆寫:

void test_lambda(TestLambda& obj) { 
    obj.data.push_back(0x01); 
} 

你現在正在做的

void test_lambda(TestLambda& obj) { 
    [=]() mutable { 
     objCopy.data.push_back(0x01); 
    }(); 
} 

其中objCopy被捕獲的λ值創建或許說明。

+0

我寫了這個片段以便能夠表達我的問題。問題不在於如何編寫函數來改變obj。 –