簡體   English   中英

檢查std :: vector的大小是否為零

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM