2013-07-25 32 views
4

考慮下面的代碼:lambda函數中引用/值的捕獲成本?

#include <iostream> 
#include <algorithm> 
#include <numeric> 

int main() 
{ 
    const unsigned int size = 1000; 
    std::vector<int> v(size); 
    unsigned int cst = size/2; 
    std::iota(v.begin(), v.end(), 0); 
    std::random_shuffle(v.begin(), v.end()); 
    std::cout<<std::find_if(v.begin(), v.end(), [&cst](const int& i){return i == cst;})-v.begin()<<std::endl; 
    std::cout<<std::find_if(v.begin(), v.end(), [=](const int& i){return i == cst;})-v.begin()<<std::endl; 
    return 0; 
} 

此代碼填充一個矢量與值,打亂它然後搜索指定的值的索引(它只是爲了說明我的問題的示例)。該值cst可以通過引用或通過lambda函數中的值捕獲。

我的問題:這兩個版本在性能上有差異,還是它們會被編譯器以相同的方式進行優化?

是一個很好的規則,通過引用(如在正常函數中)通過值和常量類傳遞常量基本類型?

+0

Vincent是任何人對您滿意的答案 – aaronman

+0

我知道您已經接受了答案,但需要考慮的一件有趣事情是,通過值捕獲是默認常量,這意味着它可以輕鬆地優化複製整個obj,因爲它不會被更改 – aaronman

回答

6

在實踐中,對於小類型沒有性能差異。

With clang -O3在兩種情況下,我都得到相同的代碼。如果沒有優化,clang會生成不同的代碼,並且複製版本恰好小於一個指令。

$ clang ref.cpp -O3 -std=c++11 -S -o ref.s 
$ clang cpy.cpp -O3 -std=c++11 -S -o cpy.s 
$ diff ref.s cpy.s 

有一個小的const相關的區別。

複製捕獲爲您提供const unsigned值。這將不編譯

unsigned cst = 123; 
[=](const int& i){ return i == ++cst; } 

在一個非const unsigned&參照一個非const變量結果的參考捕獲。此修改原始值作爲一個副作用:

unsigned cst = 123; 
[&](const int& i){ return i == ++cst; } 

作爲好的規則複製大型物體應該避免。如果小對象應該在lambda範圍內保持不變,但在當前範圍內不是常量,則複製​​捕獲是一個不錯的選擇。如果lambda的生命週期超過本地對象的生命週期,則複製捕獲是唯一的選擇。

+1

「複製捕獲給你一個const無符號值。」除非它是'mutable':'[=](const int&i)mutable {return i == ++ cst; }' – newacct

+0

@newacct很好,我沒有意識到這一點。此外,鏗鏘似乎只使全局/文件靜態/本地捕獲變量常量,但不是函數靜態/類靜態/成員變量。 – kunysch

+0

明顯的非const拷貝捕獲實際上捕獲[this]而不是單個函數static/class static/member變量。 – kunysch

1

cstunsigned int所以它不太可能有所作爲。然而,如果你在一個有大量數據的大類中做這件事,它可能會有所作爲,通過引用傳遞會更快。

在這種情況下需要考慮的另一件事是該對象僅在迭代向量時被複制一次。如果你看看STL函數,大部分事情都是通過const引用或正常引用傳遞的,我不明白爲什麼捕獲變量應該有任何不同。雖然不幸的是,你不能捕獲一個變量爲const。

當然,因爲你可以修改它,所以當你通過引用傳遞時你總是要小心,我認爲在這種情況下,作爲const引用傳遞可能會更好。

要考慮的最後一件事是,由於編譯器可能能夠優化差異,所以應該使用您認爲最適合您的意圖的表單。所以基本上我同意你的假設,你應該

通恆基本類型的值和不變的類參考

2

拉姆達捕獲是不是真的有關。所不同的是之間:和

int x = y; 

for (...) 
    if (x == z) 
     ... 

const int& x = y; 

for (...) 
    if (x == z) 
     ... 

即,存儲參考const int的VS服用copy.of一個int。第一個版本永遠不會變慢,但我認爲優化器將設法爲這兩個版本生成相同的代碼。編譯這兩個版本,並反彙編,看看會發生什麼。

+1

這個傢伙vincent問了很多問題 – aaronman

相關問題