[英]Passing std algorithm iterator parameters by value vs. by reference
我想知道為什么在STL中的許多模板算法中,參數不是通過引用傳遞的,而是通過值傳遞的。 以下是<iterator
>標頭中的示例:
template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (InputIterator first, InputIterator last);
當我將兩個迭代器傳遞給此函數時,它們將被復制。 我天真的想法是,最好通過const-reference傳遞這些迭代器,以避免復制迭代器對象:
template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (const InputIterator &first, const InputIterator &last);
可以說迭代器通常是非常小的對象,復制它們並不昂貴。 但即便如此:便宜的復制將比沒有復制更昂貴。
那么在STL版本中,迭代器是按值傳遞的原因是什么?
謝謝!
我想到的一件事是反對引用中的const
:使用它們時需要修改迭代器。
另一個實現細節可能是迭代器實際上只是作為指針實現的。 大多數情況下參考也是如此。 如果按值傳遞指針,則將其復制一次,但僅在需要時取消引用。 然而,如果迭代器指針本身是由參考指針傳遞, 那么必須首先解除引用,只是為了得到迭代器,並且必須在每次迭代器訪問的時間內完成。 這是多余的。
對於某些廉價復制類型,按值傳遞它們實際上比通過引用傳遞更快。 來自教程等的傳統智慧指出,通過引用更快,但這不一定適用於廉價復制類型。
你如何按價值傳遞一個對象? 您復制它,這意味着您獲取值並將其推送到堆棧以進行函數調用。 你如何通過參考傳遞? 您將內存地址推送到堆棧,然后被調用的函數必須獲取該地址的任何內容。 現在,優化和緩存可能會發揮作用,使內存提取更便宜,但你仍然沒有比從堆棧中獲取精確值更便宜。 在迭代器的情況下,通常只需要一個簡單的指針。 這是一個字長,復制非常便宜。
另外,請注意您建議傳遞const引用。 這意味着它必須在被調用的函數中被復制以允許它被修改(例如在循環中遞增)。
std
迭代器的概念是指針的泛化 。 std
容器的迭代器通常實現為組成單個指針的類型。 如果參數類型與指針一樣便宜,則通過引用傳遞參數比通過值傳遞更昂貴。 必須先取消引用對象,然后才能使用對象的值。 有關詳細信息,請參閱此答案 。
因為幾乎所有的std
算法都需要復制迭代器,為了獲得最佳性能,迭代器的復制成本非常低。 出於這個原因,找到一個迭代器是非常不尋常的,它通過值傳遞比引用要貴得多。
在std::distance
- 以及許多其他算法的情況下 - 整個算法非常簡單,編譯器很可能會內聯調用。 如果內聯調用,則參數是通過引用還是通過值傳遞並不重要。 [請注意,內聯函數調用與內聯函數聲明不同!]
如果迭代器通過值傳遞比通過引用更昂貴,並且函數調用沒有內聯,則可以通過rvalue-reference創建用於傳遞迭代器的參數。 在這種罕見情況下的性能提升可能不值得額外的復雜性。
大多數算法會修改其參數。 例如, distance
可以實現如下1 :
template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (InputIterator first, InputIterator last) {
typename iterator_traits<InputIterator>::difference_type result{};
while (first++ != last)
++result;
return result;
}
顯然,如果您first
作為const
引用傳遞,則不起作用。
如果將它作為非const
引用傳遞它也不起作用,因為在大多數調用上下文中,調用者的對象不能被修改(例如,如果將container.begin()
的結果傳遞給函數。
當然你仍然可以通過const
引用傳遞,在函數內部復制然后修改它。 在那一點上,我們什么都沒得到。
再加上C ++標准建議,迭代器應該是輕量級類型,復制起來應該很便宜,它更簡單,在大多數情況下通過值傳遞它們更有效 :
但即便如此:便宜的復制將比沒有復制更昂貴。
不對。 您還需要復制引用(在非內聯函數調用的情況下,它將作為指針實現)。 然后你需要取消引用那個也會增加開銷的指針。 與在許多情況下復制指針一樣便宜的直接拷貝相比,並且不會產生任何解除引用的開銷。
1當然,實際的實現將針對隨機訪問迭代器進行優化,以使其具有常量而非線性運行時。 以上實施僅供參考。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.