【发布时间】:2012-09-24 07:39:32
【问题描述】:
根据 Stroustrup : C++ 编程语言 :-
“当一个 vector 被调整大小以容纳更多(或更少)元素时,它的所有元素可能 搬到了新的位置。”
即使将矢量重新调整为更小的尺寸,这是否成立?
【问题讨论】:
-
接受的答案是错误的,如果引用来自标准的错误部分,则提供标准的引用并不能使答案正确:)
根据 Stroustrup : C++ 编程语言 :-
“当一个 vector 被调整大小以容纳更多(或更少)元素时,它的所有元素可能 搬到了新的位置。”
即使将矢量重新调整为更小的尺寸,这是否成立?
【问题讨论】:
案例 1: 如果请求的新大小大于当前的 std::vector::capacity(),则所有元素都将被重新定位。
案例 2: 如果新的请求的大小小于当前的std::vector::capacity(),则不会重新定位元素。
标准证据:
标准定义vector::resize()的效果为:
C++11标准23.3.6.3/12向量容量:
void resize(size_type sz, const T& c);
效果:
if (sz > size())
insert(end(), sz-size(), c);
else if (sz < size())
erase(begin()+sz, end());
else
; // do nothing
正如@DavidRodríguez-dribeas 正确指出的那样,std::vector::insert() 操作的迭代器失效规则是:
23.3.6.5 矢量修饰符
1 [插入,push_back,emplace,emplace_back]
备注:如果新大小大于旧容量,会导致重新分配。如果没有发生重新分配,则插入点之前的所有迭代器和引用仍然有效。
基本上这意味着:
插入点之前的所有迭代器和引用都不会受到影响,除非新容器大小大于先前的容量,因为在这种情况下,所有元素都可能被移动到新位置,从而使指向原始位置的指针/迭代器无效。因为 resize() 仅删除/插入容器末尾的元素[注 1]。控制因素归结为根据当前容量请求的大小。
因此是案例 1 的结果。
在案例2中会调用std::vector::erase(),这种情况下的失效规则是:
23.3.6.5 矢量修饰符
迭代器擦除(const_iterator position);
3 效果:在擦除点或之后使迭代器和引用无效。
由于[注1],元素只会在最后被移除,不需要重新定位所有元素。
【讨论】:
capacity() 和size() 如何影响场景。您可以将标准中的相关resize() 引用添加到你的答案。一旦 OP 取消接受,我将删除这个答案(我不能删除,直到它被接受)
...元素可能会被移动到新的位置。”
注意上面写着可能会被移动。所以这意味着它取决于它是什么类型的调整大小。
【讨论】:
向量中的迭代器因两个原因而失效。如果向量需要增加其容量,则在迭代器 (1) 的位置之前插入/删除元素或重新定位整个缓冲区 (2)。这里的关键是更改capacity()。
因为resize() 仅从容器末尾插入/删除。当向量收缩时,只有那些引用被删除元素的迭代器才会失效。当向量增长时,如果新大小小于capacity(),则没有迭代器无效,如果新大小更大,则所有迭代器都将失效。
由于 Als 提供了不正确的证据1,我在此添加正确的引号:
23.3.6.5 矢量修饰符
1 [插入,push_back,emplace,emplace_back]
备注:如果新大小大于旧容量,会导致重新分配。如果没有发生重新分配,则插入点之前的所有迭代器和引用都保持有效。
2 [擦除]
效果:在擦除点或之后使迭代器和引用无效。
类似的引号可以在 C++03 中找到。
1 避免重复引用指示resize 等效于插入或擦除的引用。哪个是对的。
【讨论】:
问题正文中的答案“”当调整向量的大小以容纳更多(或更少)元素时,它的所有元素都可能是搬到了新的位置。""
【讨论】: