[英]C++ - Performance of vector of pointer to objects, vs performance of objects
在這種情況下,問題場景是游戲,因此所有資源在開始時分配,然后迭代一個級別。
存儲在向量中的對象是復雜類的實例,當然在加載時將它們實際復制到向量中是耗時的,但是關注度低。
但是如果我主要擔心的是在運行時對類對象進行迭代的速度,那么我是否更好地將類對象本身存儲在向量中,而不是像傳統推薦的那樣只指向類對象?
我不擔心這個例子中的內存管理,只是迭代的速度。
我遲到了回答這個問題,但是性能方面很重要,到目前為止在線答案純粹是理論上和/或專注於內存管理方面。 所以這里是我最近嘗試的三個相關場景的一些實際基准信息。 你的結果可能會有所不同,但至少有一些想法可以解決實際應用中的問題。
這里引用的類A
有大約10個成員字段,其中一半是基元,另一半是std::string
, std::vector<int>
,以及其他動態大小的容器。 該應用程序已經相當優化,因此我們希望看到哪個架構現在為我們提供了最快的A
集合循環。 任何A
對象的成員字段的值可能會在應用程序生命周期中發生變化,但是向量中的A
對象數量不會在我們執行的多次重復迭代中發生變化(此連續迭代構成此應用程序執行時間的約95%) 。 在所有情況下,使用典型的std::iterator
或std::const_iterator
執行循環。 每個枚舉的A
對象至少訪問了幾個成員字段。
場景1 - 對象指針向量
盡管最簡單, std::vector<A*>
這種架構結束時比其他架構略慢。
場景2 - 對象指針向量,對象使用新的位置分配
這種方法背后的想法是我們可以通過強制將對象分配到連續的內存空間來改善緩存的局部性。 因此, std::vector<A*>
對象指針的保證是由連續std::vector
實現和A
對象本身也將是連續的堆,因為我們使用了新的安置成語。 我使用了這個答案中概述的相同方法; 有關安置新的更多信息,請點擊此處 。
此方案比方案1快2.7%。
場景3 - 對象矢量
這里我們直接使用std::vector<A>
。 std::vector
實現保證了我們的A
對象在內存中是連續的。 請注意,對象的std::vector
確實涉及A
的移動和復制構造函數的注意事項。 為了避免不必要的移動和/或重建,最好std::vector.reserve()
最大可能需要的大小(如果可能),然后使用std::vector.emplace_back()
(而不是push_back()
)如果可能的話。 循環這個結構是最快的,因為我們能夠消除一個指針間接層。
這種方法比方案1快6.4%。
對不同問題的相關答案還表明,普通對象(作為類成員)可以比相應的指針(作為類成員)快得多。
第一件事就是指針應該用來存放笨重的東西。 因為如果使用對象數組,如果要創建n個龐大的對象並每次復制它們存儲它(這也是一個很大的代價)而第二件事如果你使用向量(STL)每次向量大小增加記憶 主要成本是復制第一秒的數據,這實際上是主要成本,即復制。 此成本也是內置使用時可能產生的最低成本。
不,她沒有錯,她是絕對正確的,雖然你只詢問快速迭代,但這有很多與內存的聯系...更多內存堆棧將更慢訪問...
我有一個現場演示......
#include <iostream>
#include <string>
#include <vector>
#include "CHRTimer.h"
struct Items
{
std::string name;
int id;
float value;
float quantity;
};
void main()
{
std::vector<Items> vecItems1;
for(int i = 0; i < 10000; i++)
{
Items newItem;
newItem.name = "Testing";
newItem.id = i + 1;
newItem.value = 10.00;
newItem.quantity = 1.00;
vecItems1.push_back(newItem);
}
CHRTimer g_timer;
g_timer.Reset();
g_timer.Start();
for(int i = 0; i < 10000; i++)
{
Items currentItem = vecItems1[i];
}
g_timer.Stop();
float elapsedTime1 = g_timer.GetElapsedSeconds();
std::cout << "Time Taken to load Info from Vector of 10000 Objects -> " << elapsedTime1 << std::endl;
std::vector<Items*> vecItems;
for(int i = 0; i < 100000; i++)
{
Items *newItem = new Items();
newItem->name = "Testing";
newItem->id = i + 1;
newItem->value = 10.00;
newItem->quantity = 1.00;
vecItems.push_back(newItem);
}
g_timer.Reset();
g_timer.Start();
for(int i = 0; i < 100000; i++)
{
Items *currentItem = vecItems[i];
}
g_timer.Stop();
float elapsedTime = g_timer.GetElapsedSeconds();
std::cout << "\nTime Taken to load Info from Vector of 100000 pointers of Objects -> " << elapsedTime;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.