std
假設函數對象並且迭代器可以自由複製。
std::ref
提供了一種方法來將函數對象轉換爲具有兼容的operator()
的僞引用,該引用使用引用而不是值語義。所以沒有什麼大的價值會丟失。
如果你被教導過你所有的生活,以參考的方式提取對象,請重新考慮。除非有充分的理由,否則以價值爲目標。對價值的推理要容易得多;引用是指向程序中任何位置的任何狀態的指針。
引用的常規用法,作爲指向本地對象的指針,在使用它的上下文中沒有被任何其他活動引用引用,這不是某人閱讀您的代碼,也不是編譯器可以推測的。如果你以這種方式推理引用,它們不會爲你的代碼增加一些荒謬的複雜性。
但是,如果你以這種方式推斷他們,那麼當你的假設被違反時,你將會有錯誤,並且他們會微妙,粗暴,意外和可怕。
一個典型的例子是operator=
的數量,當this
和參數引用同一個對象時會中斷。但是任何帶有兩個引用或同一類型指針的函數都有相同的問題。
但即使一個參考可能會破壞您的代碼。我們來看看sort
。在僞代碼:
void sort(Iterator start, Iterator end, Ordering order)
現在,讓我們訂購的參考:
void sort(Iterator start, Iterator end, Ordering const& order)
這件怎麼樣?
std::function< void(int, int) > alice;
std::function< void(int, int) > bob;
alice = [&](int x, int y) { std:swap(alice, bob); return x<y; };
bob = [&](int x, int y) { std:swap(alice, bob); return x>y; };
現在,打電話sort(begin(vector), end(vector), alice)
。
每次調用<
時,所指的order
對象交換含義。現在,這是非常荒謬的,但是當你通過const&
了Ordering
,優化必須考慮到這種可能性,並排除它在你的訂貨代碼每invokation!
你不會做以上(實際上這個特定的實現是UB,因爲這將違反有關std::sort
任何合理的必要條件);但是編譯器必須證明你每次執行order
或調用它時都沒有「做那樣的事」(更改ordering
中的代碼)!這意味着不斷重新加載order
的狀態,或內聯並證明你沒有任何精神錯亂。
按值時服用這樣做是一個數量級的更硬(並且基本上需要像std::ref
)。優化器有一個函數對象,它是本地的,它的狀態是本地的。存儲在其中的任何內容都是本地的,編譯器和優化器知道誰可以合法修改它。
您編寫的每個函數都會保留其「本地範圍」(稱爲C庫函數)的const&
,它不能假定const&
的狀態在返回後保持不變。它必須從指針指向的任何地方重新加載數據。現在
,我沒有說按值傳遞,除非有很好的理由。有很多很好的理由。例如,您的類型移動或複製的費用非常高,這是一個很好的理由。您正在向其寫入數據。你實際上希望它隨着你每次閱讀而改變。等
但默認的行爲應該是傳遞的價值。只有在有充分理由的情況下才會轉向參考,因爲成本是分散的,難以確定。
另請參閱:http://stackoverflow.com/questions/34825552/passing-function-objects-into-std-algorithms-by-reference – NathanOliver
[sizeof on a stateless lamb返回1](http:// coliru。 stacked-crooked.com/a/ef6ae126ba68338b) – jaggedSpire
複製不包含數據的lambda的成本是多少?優化後,什麼也沒有。在複製elision優化之後,複製甚至是複雜函子的成本可能爲零。 –