2012-01-05 77 views
7

假設我有INTS的載體,矢量指針位置有保證嗎?

std::vector<int> numbers; 

被填充了一堆價值的,後來我說做這個(其中一個條目,爲43存在)

int *oneNumber = &numbers[43]; 

是oneNumber保證總是指向索引43處的int,即使我說我將數字調整爲諸如numbers.resize(46)之類的東西?

我不是100%確定這裏預期的行爲是什麼,我知道向量保證是連續的,但不確定這個連續性是否也意味着向量中的所有索引在整個生命週期中都保持在同一個地方。

+0

出於這個原因,我總是小心翼翼創造價值類型的載體,因爲我必然需要一個指向矢量內的對象。所以我保存了一個引用,例如'int * ref =&numbers [43]'..稍後,將'push_back'變成'numbers'和WHAMMO!錯誤:'ref'是無效的,因爲'numbers'已經完全重新分配並保存在完全不同的內存空間中。 – bobobobo 2013-01-05 00:41:58

+0

@bobobobo非常真實。儘管在創建時已知元素數量的情況(並且不能,我不能使用'std :: array',因爲我'emplace'-通過循環構造值),'reserve'保證所有的指針/迭代器進入向量將保持有效,只要它的大小不超過當前的容量(這可能迫使重新分配並因此移動所包含的值的地址)。這爲我節省了幾次,但是每次連續的時間,我都忘記「保留」,並且在我記憶的時候,劃傷我的頭腦一段時間。 :D – 2016-01-12 18:46:49

回答

7

是oneNumber保證總是在INT在索引43

是,這是通過標準的保證被指向。

即使說我調整數字的大小像numbers.resize(46)?

不是。一旦你調整大小,向vector中添加或刪除任何東西,所有地址和迭代器都將失效。這是因爲該向量可能需要重新分配新的內存位置。

+0

如果你使用'std :: list',那麼怎麼辦?如果你只使用'list.push_back()'調用添加項目,是否會繞過無效地址問題? (並且你不刪除'oneNumber'指向的項目? – bobobobo 2012-09-29 02:53:42

+0

@bobobobo這是一個很好的問題,我不確定標準對此有什麼看法,但我沒有理由在std中添加/刪除: :list'將使任何指針無效(除去被刪除的元素)[如果你想加入,我們現在在休息室討論它。](http://chat.stackoverflow.com/transcript/message/5559322 #5559322) – Mysticial 2012-09-29 03:00:40

+0

找到[另一個解決方法](http://stackoverflow.com/a/12771369/111307)我正在使用。 – bobobobo 2012-10-07 18:05:05

2

否 - 矢量可以在增長時重新分配。通常情況下,矢量的大小會增加一倍。

從C++ 11標準

1 Remarks: Causes reallocation if the new size is greater than the old capacity. If no 
reallocation happens, all the iterators and references before the insertion point 
remain valid. If an exception is thrown other than by the copy constructor, move 
constructor, assignment operator, or move assignment operator of T or by any 
InputIterator operation there are no effects. If an exception is thrown by the move 
constructor of a non-CopyInsertable T, the effects are unspecified. 
4

你的偏執是對的。調整std::vector的大小可能會導致其內存位置發生更改。這意味着您的oneNumber現在指向已被釋放的舊內存位置,因此訪問它是未定義的行爲。

2

當您使用矢量的resize()或reserve()函數來增加矢量的容量時,它可能需要重新分配用於數組支持的內存。如果它重新分配,新的內存將不會位於同一地址,因此存儲在oneNumber中的地址將不再指向正確的位置。

同樣,這取決於矢量當前被用來存儲的元素數量和請求的大小。根據具體情況,矢量可以在不重新分配的情況下調整大小,但您絕對不應該認爲情況會如此。

4

指針,引用和迭代器std::vector元素,保證留只要你只能追加到std::vectorstd::vector的大小不當時的指針,引用增長超過其capacity()說,或獲得迭代器。一旦它被調整大小超出capacity(),所有指針,引用和這個std::vector的迭代器都將失效。請注意,在插入除std::vector的末尾以外的地方時,事物也會失效。

如果您希望讓對象保持放置狀態,並且只在最後或開始插入新元素,則可以使用std::deque。指向std::deque中元素的指針和引用僅當您插入到std::deque的中間或從中間刪除或刪除引用對象時纔會失效。請注意,每次向std::deque中插入元素或從中刪除任何元素時,std::deque中元素的迭代器都會失效。

2

一旦你改變了矢量的容量,數據被複制到另一個存儲塊,並且原點數據被刪除。

3

正如所有其他人所說的,當你在一個向量上調用.resize()時,指針會失效,因爲(舊數組)可能會被完全釋放,並且可能會重新分配一個全新的數據,並將數據複製到其中。

對此的一種解決方法是不要將指針轉換爲STL向量。相反,存儲整數索引

在你的榜樣

所以,

std::vector<int> numbers; 
int *oneNumber = &numbers[43]; // no. pointers invalidated after .resize or possibly .push_back. 
int oneNumberIndex = 43 ;  // yes. indices remain valid through .resize/.push_back