![](/img/trans.png)
[英]how does the short(vector.size()) command conversion work in C++?
[英]how much work is done by calling vector.size()?
這是一個簡單的吸氣劑嗎? 還是每次計算?
如果我有這樣的for循環:
for (int i = 0; i < myVector.size(); i++) { }
我只需要使用一次大小,在循環之前計算一次並將其存儲在變量中會更好嗎? 或者size()只是一個簡單的吸氣劑,它會有什么不同?
這是實現定義。 假設實現想要提供有效的標准庫,那么兩個最可能的實現是:
無論如何,標准要求復雜性是恆定的,你不應該真的擔心它。 此外,編譯器經常進行優化,以便自行存儲您的大小。
使用迭代器而不是這樣的循環來獲得更大的靈活性和genrosity:
std::vector<int>::const_iterator iter = myVector.begin();
for(iter; iter!= myVector.end(); ++iter)
{
}
這可以確保如果在開發的后期更改容器,則代碼的耦合程度會降低。
在我看過的每個實現中,它都是每次計算的 - 在O(1)中 - 通過從結尾開始減去。 所以,它幾乎沒有什么區別。 編譯器可能會或可能不會優化“計算”,但時間是如此微不足道,以至於除了最絕望的情況之外的所有人都無關緊要。
在你看來,使用任何更易於維護的東西:無論讀取效果如何,最好地定位邏輯等等。可以說值得注意的是,在使用size()時,即使在循環體內有刪除或插入,也要確保准確跟蹤向量的末尾。因此,可能有功能上的原因要求(或避免)重復調用size()。
請注意,對於STL列表,size()不是常量時間 - 它是線性的。
http://www.cplusplus.com/reference/stl/vector/size/表明操作的復雜性是不變的。 這意味着每次調用size()
時都不會重新計算size()
,或者在大多數情況下開銷可以忽略不計。 所以在你的代碼中使用它就好了:這不會是你代碼的瓶頸。 (除非這是一個緊密的內循環,每次優化都會帶來很多。)
此外,如果要在循環內更改向量,您將會更安全(但不是完全安全!)。
如果你看一下vector :: size()的實現
size_type size() const
{ // return length of sequence
return (_Mylast - _Myfirst);
}
其中_Mylast和_Myfirst是指針。
它只是一個指針算術,應該是一個原子操作。 因此它不應該是一個開銷!
也許您實際上想知道編譯器是否可以確定size()
函數返回的值永遠不會改變並將其提升出循環。 雖然這看起來很合理,但編譯器必須能夠證明提升產生與您編寫的版本完全相同的行為(即每次調用“似乎” size()
),並且有多遠編譯器可以看到,或者實際上可以看到它實際可證明的程度。
因此,如果您知道沒有更改容器的大小,則應手動編寫提升機:
// index version:
for (std::size_t i = 0; end = v.size(); i != end; ++i) { work_with(v[i]); }
// iterator version:
for (auto it = v.begin(), end = v.end(); it != end; ++it) { work_with(*it); }
對std::vector::size()
調用具有恆定的復雜性,即它們的成本與向量中的元素數量無關,但仍可能存在成本。 在最好的情況下,你只是簡單地讀取一個變量(所以在一個副本的提升和非提升版本的循環中沒有區別),但實現執行指針減法也是可行的。
計算std::vector
的size()
需要恆定的時間,但計算可能比兩個指針之間的差異更大。 雖然這似乎是一種廉價的計算,但它增加了對可用寄存器的限制。 此外, std::vector
其他實現在size()
需要更多的努力,但使其他操作更有效。
例如,對於許多用例,最好只用一個指向范圍起點的指針和前面這個范圍的控制數據來表示一個std::vector
。 奇怪的是,這種情況發生在使用數組分配分配的內存通常是如何布局的。 控制數據將包含兩個指針(一個指向范圍的末尾,另一個指向容量)。 在這種情況下獲得大小包括地址調整(雖然具有固定大小),指針取消引用和減法。 仍然不是很多但是你在[緊]循環中做的越少,它運行得越快(在大多數情況下)。
結果是:除非容器正在改變其大小,否則只獲取size()
和end()
一次。 如果它正在改變大小,它取決於容器的類型是否你應該重新計算東西:例如對於std::list
你不需要再次獲得end()
(並且你不想得到它的size()
你絕對不得不這樣做。 我似乎記得斯科特邁耶斯在“有效STL”中討論過這個話題,但我不記得他是否說過我剛剛做過的事(或者他是不是錯了;)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.