2017-05-25 194 views
3

我遇到一個問題,我不太明白:讓指針矢量元素

我與

edge_vec1.push_back(Edge(src,dest)); 

創建對象邊緣然後我想一個指針保持這一邊緣單獨的載體:

edge_vec2.push_back(&edge_vec1.back()); 

然而,一旦添加,指針向第一邊緣在edge_vec2無效所述第二邊緣對象(得到一些隨機數據)。是否因爲edge_vec2中的指針實際指向edge_vec1中的某個位置,而不是指向底層元素?我可以通過在堆上創建我的Edge對象來避免這種情況,但我想知道發生了什麼。

謝謝。

+1

爲什麼要在第一個地方存儲一個指向數組元素的指針?你不能只存儲一個索引? – InternetAussie

+0

@InternetAussie那麼,我確實將元素存儲在第一個向量中。但假設第一個容器實際上是更復雜的東西,例如鄰接表。然後沒有索引,但我想保留一個選項來快速迭代所有的邊緣 – LazyCat

+0

最簡單的解決方案是將指針存儲在兩個容器中並動態創建對象。 – Logman

回答

2

當一個新的元素被添加到一個向量中時,該向量可以被重新分配。因此,指向矢量元素的指針的先前值可能無效。

您應該首先爲防止重新分配的向量預留足夠的內存。

edge_vec2.reserve(SomeMaxValue); 
+0

謝謝,我懷疑這是怎麼回事。我想,如果可用的值只是作爲一個向量元素,它不能有一個永久指針。 – LazyCat

+0

不是如果你可能增長矢量,沒有。 –

+0

@DanielH我認爲表示邊的元素的數量對於給定的圖是固定的。 –

3

http://en.cppreference.com/w/cpp/container/vector/push_back

如果新的大小()比容量大(),那麼所有的迭代器和引用(包括過去的最末端迭代器)無效。否則只有最後一個迭代器失效。

當您向其中添加項目時,依靠指向vector中的對象的指針/引用是個壞主意。最好存儲索引的值,然後使用索引從vector中獲取項目。

edge_vec2.push_back(edge_vec1.size()-1); 

之後,你可以使用:

edge_vec1[edge_vec2[i]] 

i一些有效的價值。

+0

指數不適合我(見評論),但謝謝你的確認,我的指針會失效。 – LazyCat

1

std :: vector的要求是底​​層存儲是連續的內存塊。因此,當你想要插入一個元素時,一個向量必須重新分配它的所有元素,但是當前分配的塊不夠大,不足以容納額外的元素。發生這種情況時,所有迭代器和指針都會失效,因爲完整的塊會被重新分配(移動)到完全不同的內存部分。

成員函數容量可用於查詢可以插入的最大元素數量,而無需重新分配底層內存塊。實施例一碼查詢此:

std::vector<int> vec; 
for(int i = 0; i < 1000; i++) { 
    bool still_has_space = vec.capacity() > vec.size(); 
    if (!still_has_space) std::cout << "Reallocating block\n"; 
    vec.push_back(i); 
} 

如果連續內存佈局是不需要的有力保證,你可能會使用std :: deque的,而不是的std ::向量的更好。它允許在任何一端推動元件,而不用在任何其他元件周圍移動。你交易這個稍微差一點的迭代速度。

std::deque<int> deq; 
std::vector<int*> pointers; 
for(int i = 0; i < 1000; i++) { 
     deq.push_back(i); 
     pointers.push_back(&deq.back()); 
} 
for(auto p : pointers) std::cout << *p << "\n"; // Valid