2009-09-22 170 views
33

我的代碼std :: vector reserve()和push_back()比resize()和數組索引快,爲什麼?

void ConvertToFloat(const std::vector<short>& audioBlock, 
        std::vector<float>& out) 
{ 
    const float rcpShortMax = 1.0f/(float)SHRT_MAX; 
    out.resize(audioBlock.size()); 
    for(size_t i = 0; i < audioBlock.size(); i++) 
    { 
     out[i] = (float)audioBlock[i] * rcpShortMax; 
    } 
} 

塊上做一個快速的性能測試,我很高興與加速比原先很天真的實現它只需在1毫秒處理65536個音頻採樣。

但只是爲了好玩我嘗試以下

void ConvertToFloat(const std::vector<short>& audioBlock, 
        std::vector<float>& out) 
{ 
    const float rcpShortMax = 1.0f/(float)SHRT_MAX; 
    out.reserve(audioBlock.size()); 
    for(size_t i = 0; i < audioBlock.size(); i++) 
    { 
     out.push_back((float)audioBlock[i] * rcpShortMax); 
    } 
} 

現在我完全可以預料這給完全相同的性能,因爲原代碼。然而突然間,循環現在需要900usec(即比其他實現快100倍)。

任何人都可以解釋爲什麼這會提供更好的性能? resize()初始化新分配的向量,其中保留只分配但不構造?這是我能想到的唯一的事情。

PS在單核2Ghz AMD Turion 64 ML-37上進行了測試。

+0

例行檢查時,編譯代碼時使用的是釋放而不是調試設置? – Laserallan 2009-09-22 17:15:25

+0

hehehe,是的,我正在使用發佈。這是關於幫助編譯器幫助我的更多問題:) – Goz 2009-09-22 18:25:52

回答

52

是否調整大小初始化新分配的矢量,其中保留只分配但不構造?

是的。

+0

SGI的STL參考文獻解釋了調整大小「在最後插入或擦除元素」,而保留只是執行內存分配。 http://www.sgi.com/tech/stl/Vector.html – user7116 2009-09-22 17:05:37

+0

這是如何工作的? malloc的? – pyon 2009-09-22 17:06:42

+0

它將使用分配器爲矢量設置的任何值。 – user7116 2009-09-22 17:09:30

1
out.resize(audioBlock.size()); 

由於out的大小(= 0)低於audioBlock.size()較小,被創建並附加到out的端部的附加元件。這通過調用它們的默認構造函數來創建新的元素。

保留只分配內存。

3

第一個代碼寫入out[i],歸結爲begin() + i(即加法)。第二個代碼使用push_back,它可能立即寫入相當於end()的已知指針(即不添加)。通過使用迭代器而不是整數索引,您可以使第一次運行速度與第二次運行速度一樣快。

編輯:也澄清一些其他意見:載體含有浮標,構建浮子實際上是一個無操作(以同樣的方式,宣佈「浮動的f;」不發射碼,只告訴編譯器爲堆棧上的浮點節省空間)。所以我認爲對於浮動矢量而言,resize()reserve()之間的任何性能差異與建築無關。

+3

對不起,但你的建設點是不真實的。 float f = 0.0f;顯然比「float f;」慢。後者是前者不是前者。 – Goz 2009-09-22 17:16:40

+0

哦,公平點,不知道構造一個賦值爲0的浮點數。向量在調整大小時將T()賦值給每個元素,即float(),該值爲0.仍然使用迭代器代替整數索引可能會更快。 – AshleysBrain 2009-09-22 17:28:02

3

調整尺寸()

修改所述容器,以便它具有恰好n個元素,在插入端部元件,或者如果需要,在從結束擦除元件。如果插入了任何元素,則它們是t的副本。如果n > a.size(),這個表達式相當於a.insert(a.end(), n - size(), t)。如果是n < a.size(),則相當於a.erase(a.begin() + n, a.end())

預訂()

如果n小於或等於capacity(),此調用將不起作用。否則,它是分配額外內存的請求。如果請求成功,則capacity()大於或等於n;否則,capacity()不變。無論哪種情況,size()都不變。

如果超過capacity() - size()元素插入向量中,內存將自動重新分配。重新分配不會改變size(),也不會更改矢量的任何元素的值。但是,它確實增加了capacity()

保留導致手動重新分配。使用reserve()的主要原因是效率:如果您知道矢量最終必須增長的容量,那麼一次分配內存通常更有效,而不是依賴於自動重新分配方案。

相關問題