2011-04-21 52 views
2

的我目前填充元素的矢量陣列像這樣:陣列連續的新對象

std::vector<T*> elemArray; 

    for (size_t i = 0; i < elemArray.size(); ++i) 
    { 
    elemArray = new T(); 
    } 

的代碼已經明顯被簡化。現在問陸續question(無關的這個問題,但相關的程序),我意識到我需要有new'd對象的數組(不能是在棧上,就會溢出,太多的元素),但是是連續的。也就是說,如果我要接收一個沒有數組索引的元素,我應該通過執行returnedElement - elemArray[0]來查找數組索引,以獲取數組中元素的索引。

我希望我已經解釋過這個問題,如果沒有,請讓我知道哪些部分,我將試圖澄清。

編輯:我不知道爲什麼最高的投票答案沒有被調查。我已經嘗試了很多次。如果我嘗試分配超過100,000(大約)元素的矢量,它總會給我一個內存錯誤。其次,我需要指點,從我的例子可以清楚看出。突然改變它不是指針將需要大量的代碼重新寫的(雖然我很願意這樣做,但它仍然沒有解決的問題是分配這樣的載體有幾百萬個元素不起作用。

+0

如果你想在_objects_是連續的,你想他們10萬,那麼你可能正在運行的地址空間。你的對象有多大,你使用的是64位平臺? – 2011-04-21 22:15:05

+0

雖然我的系統是64位,但該程序是以32位編譯的。對象大小爲192字節,這實際上不應該是一個問題(大約20mb的連續內存)。我有8GB的系統RAM。 – Samaursa 2011-04-21 22:18:12

+0

您可能會感到驚訝,您是否嘗試過在運行時映射了您的程序的地址空間?另外,我不太瞭解你的「我需要指針」的要求。如果你有一個連續的元素塊,那麼構造一個指向任何元素的指針是微不足道的。也許你可以發表一些澄清的代碼? – 2011-04-21 22:30:38

回答

1

你原來的循環應該是這個樣子:(儘管它不會產生連續內存中的對象)

for (size_t i = 0; i < someSize ; ++i) 
{ 
    elemArray.push_back(new T()); 
} 

然後你應該知道兩米基本這裏的東西:

  • elemArray.size()返回elemArray當前持有的元素數。這意味着,如果你在for循環的條件使用它,那麼你的for循環將成爲無限循環,因爲你將元素添加到它,所以向量的規模將不斷增加。
  • elemArrayT*的載體,所以你只能存儲T*,並填充它,你必須使用push_back函數。
+0

「儘管它不會在連續內存中創建對象」(鏈接中的其他問題有一個解決方案,只要我能夠將對象放置在一個連續的向量中並且已經成爲「新」 'd'某種方式...否則我得到一個壞的分配例外超過100,000 [我需要500萬]的元素] – Samaursa 2011-04-21 21:39:44

0

分配一大塊內存,並使用placement new來構建你的矢量元素在裏面:

elemArray[i] = new (GetNextContinuousAddress()) T(); 

(假設你真的需要指針indidually數組中new'ed對象,並這是爲什麼不建議知道的原因..)

+0

這正是我需要在這種情況下,但爲什麼不推薦? – Samaursa 2011-04-21 18:41:19

+0

由於您不得不手動刪除所有元素,所以不建議使用指針向量。例如,在這樣的向量上調用erase()會泄漏被刪除的指針元素。這就是智能指針的典型用途 - 它們具有釋放被指向的對象的析構函數。 – 2011-04-21 19:18:39

4

一個std::vector<>存儲其在堆中分配的數組元素,它不會存儲在堆棧上的元素。所以,你不會得到任何堆棧溢出,即使你做的簡單的方法:

std::vector<T> elemArray; 
for (size_t i = 0; i < elemCount; ++i) { 
    elemArray.push_back(T(i)); 
} 

&elemArray[0]將是一個指向T對象(連續)陣列。

+0

是的 - 現在看起來更合理。 – 2011-04-21 17:30:05

+0

我不明白,T(i)'不是指構造T並將它傳遞給參數'i'? – Samaursa 2011-04-21 18:38:25

+0

@Samaursa:是的,但是你的取決於你的'T'對象是如何構建的。那裏需要做什麼來創建你的'T'對象。 – sth 2011-04-21 18:56:48

3

如果你需要的元素是連續的,而不是指針,你可以這樣做:

std::vector<T> elemArray(numberOfElements); 

本身不會在堆棧上的元素,vector管理存儲器和在動態分配你的例子中的元素將被初始化。 (嚴格地說,從一個初始值初始化的臨時值複製初始化,但是對於它可以存儲在一個向量中的對象,這應該是相同的。)

我相信你的索引計算應該是:&returnedElement - &elemArray[0],這將起作用與vector。假設returnedElement實際上存儲在elemArray中。

1

考慮您的舊代碼導致堆棧溢出我想大概是這樣的:

Item items[2000000]; // stack overflow 

如果是這樣的話,那麼你可以使用下面的語法:

std::vector<Item> items(2000000); 

這將在堆上分配(和構建)連續的項目。

+0

我需要控制什麼時候創建它們,並且需要向量來存儲指針......就像如果我有int * a [50]有50個指針,我可以通過sizeof(int)跳過並保證是連續的。 – Samaursa 2011-04-21 21:41:45

0

我知道這是一箇舊帖子,但對於任何可能需要它的人來說,它可能是有用的英特爾。在一個序列容器中存儲指向是完全沒有問題只有當你心中有幾個重要的注意事項:

  • 您存儲的指針指向將不連續的內存,因爲他們被分配(動態或不對齊的對象)在你的程序中的其他地方,你最終會得到一個連續的指針數組,指向可能分散在內存中的數據。

  • 由於STL容器使用值複製而不引用副本,因此您的容器將不會取得分配的數據的所有權,因此只會刪除銷燬時的指針對象而不是它們指向的對象。當這些對象沒有被動態分配時,這很好,否則你需要在尖端對象的其他地方提供一個釋放機制,比如簡單地循環指針並單獨刪除它們或者使用共享指針,這些指針將在需要時爲你完成工作; )

  • 要記住的最後一件事,但是非常重要的一點是,如果你的容器被用在動態環境中,並且可能會隨機插入和刪除,你需要確保使用穩定的容器,這樣你的迭代器/指向存儲元素的指針在這些操作之後仍然有效,否則最終會產生不良的副作用...... std :: vector會導致這種情況,當插入新元素時會釋放並重新分配額外空間,然後執行移位元素的副本(除非你在最後插入),從而失效元素指針/迭代器(一些實現提供了穩定性,雖然像boost :: stable_vector,但是這裏的懲罰是你失去了容器的連續屬性,編程時魔法不存在,生命是不公平的嗎? ;-))

問候

1

雖然我也有同樣的要求,但出於不同的原因,主要是爲是緩存中的熱點?(對於小數量的對象)

int maxelements = 100000; 

    T *obj = new T [100000];   

    vector<T *> vectorofptr; 

    for (int i = 0; i < maxelements; i++) 
    { 
     vectorofptr.push_back(&obj[i]); 
    } 

int sz = sizeof(T); 
    int maxelements = 100000; 

    void *base = calloc(maxelements, sz); //need to save base for free() 

    vector<T *> vectorofptr; 
    int offset = 0; 

    for (int i = 0; i < maxelements; i++) 
    { 
     vectorofptr.push_back((T *) base + offset); 
     offset += sz; 
    }