[英]checking if a std::vector is of size zero
在vs2010 std :: vector.size()中:
return (this->_Mylast - this->_Myfirst);
和std :: vector.empty():
return (this->_Myfirst == this->_Mylast);
我的問題是,如果要檢查向量是否具有零元素,則這兩個函數之間是否存在速度差異。 負號和等於號幾乎是相同的二進制運算,那么這兩個函數的速度是否相同?
除非您每秒進行數百萬次此操作(認真地說,為什么會這樣 ?),否則不會有任何不同。
如果您真的有興趣,請檢查它。 建立一個數百萬次的循環,看看每個循環需要多長時間。
我認為您會發現差異可以忽略不計。
將精力集中在宏優化問題(例如算法選擇)上並優化此類內容以提高可讀性會更好。
而且,無論如何,針對可讀性進行優化是一種有效的方法,除非存在嚴重的性能瓶頸,否則我通常會采用這種方法。 換句話說,如果您要根據是否為空來執行某些操作,請使用empty()
或!empty()
。 任何其他大小檢查(例如其中是否至少包含十二個元素)都應使用size()
(顯然)。
作為一些微優化可能無關緊要的示例,下面是一些需要考慮的C代碼:
#include <stdio.h>
int main(void) {
int i, j, k, diff;
for (i = 0; i < 1000; i++)
for (j = 0; j < 1000000; j++)
//diff = (i == j);
diff = (i - j);
return 0;
}
當我使用默認優化(a)進行編譯並使用time
命令運行它time
,我得到的CPU時間為(超過五次運行),其中以下行之一未注釋:
diff = (i - j) diff = (i == j)
============== ===============
2.488 2.216
2.424 2.220
2.452 2.224
2.484 2.152
2.464 2.152
===== =====
Avrgs: 2.463 2.193
現在,第一種選擇的速度要慢12%,但是您需要了解一件事。 盡管速度較慢,但僅需兩秒鍾即可完成十億次。 如果只執行一次,則差異在0.000000002463秒和0.000000002193秒之間,這確實不值得進行優化。
選擇您的戰斗,針對您的優化。 通過宏優化策略,您可以大幅度提高速度。
(a)使用gcc
“瘋狂”優化級別-O3
,它們都需要0.000秒(有時是0.004,但是很少-我認為time
命令的分辨率存在限制),這使得差異變得更不相關了:-)
使用size()
empty()
size()
來檢查向量空度有兩個原因:
根據實現的不同, std::vector.empty()
可能比std::vector.size()
更快 。
與使用size()
相比,使用empty()
檢查向量的空度更直觀,更易讀。
參考:
Nicolai M.Josutil的:
C ++標准庫:教程和參考
指出:
size()
返回容器的實際元素數。
empty()
是檢查元素數是否為零( size()==0
)的快捷方式。 但是, empty()
可能會更有效地實現,因此,如果可能,應使用它。
請注意,盡管要絕對確定哪一個速度更快,但您必須為您的環境配置兩者。
對於vector,性能可能是相同的。 即使不一樣,它也具有相同的Big O復雜度,並且速度差異可以忽略不計。 因此,如果只想檢查向量是否為空,則使用empty
可能更方便。 它更准確地描述了您真正想要做什么。
使用empty
另一個原因是,當您以后將容器更改為list
,它的Big O復雜度可能會更高。 因為有一些std::list
實現,其中size
具有線性復雜度,而空則始終為O(1)。
Scott Meyers在“有效的STL”中,建議調用empty()
而不是檢查所有容器的大小。 他給出的原因是,對於所有標准容器而言, empty
是恆定時間,而在某些列表實現中, size
需要線性時間。
如果使用大小,並且稍后碰巧要更改容器,則可能會出現性能問題。
因此,除非檢查容器是否沒有元素是一個真正的瓶頸(首先測量,如果有問題就進行優化),請使用empty
。
讓我們在這里停止虛構 :
bool empty_by_difference(int* b, int* e) {
return (e - b) == 0;
}
bool empty_by_equality(int* b, int* e) {
return e == b;
}
由Clang 3.0編譯為以下IR:
define zeroext i1 @_Z19empty_by_differencePiS_(i32* %b, i32* %e) nounwind uwtable readnone {
%1 = icmp eq i32* %e, %b
ret i1 %1
}
define zeroext i1 @_Z17empty_by_equalityPiS_(i32* %b, i32* %e) nounwind uwtable readnone {
%1 = icmp eq i32* %e, %b
ret i1 %1
}
您可能不知道投資者關系代表,但我仍然認為這會奏效。
因此,讓我推測,基准測試只是我和您的時間的損失。
現在,從語義的角度來看,我個人發現讀取if (x.empty())
比讀取if (x.size() == 0)
更清晰。
在后一種情況下:
==
與!=
或<=
或>=
區別開... 0
是一種前哨值,與任何其他值(例如1
等)有很大的不同... 如果空值和大小之間存在差異,那么它甚至很小,甚至基准測試都不會看到它。 因為從C ++ 11開始,列表的大小為O(1),所以我認為寫入大小更可讀,然后為空。 但那只是我的個人意見:)
減號和等於幾乎是相同的二進制運算
確實, 幾乎一樣。 但是AFAIK布爾運算符比其他運算符要快。
不應有速度差異。 實際上,您應該看到兩種情況下生成的代碼完全相同。 編譯器應該能夠執行以下轉換:
if (vec.size() == 0)
// After inlining:
if (_Mylast - _Myfirst == 0)
// Equivalent to:
if (_Mylast == _Myfirst) // Which is the same as empty() after it is inlined
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.