2012-01-05 79 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