说我有这段代码:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec {10, 15, 20};
auto itr = vec.begin();
vec.erase(itr);
for(const auto& element : vec)
{
std::cout << element << " ";
}
return 0;
}
这给了15 20
预期的效果。现在,cppreference说this关于erase()
:
在点或之后使迭代器和引用无效 擦除,包括end()迭代器
足够公平,但这是标准给出vector::erase()
的唯一保证吗?
是否允许矢量在擦除迭代器之后重新排序它的元素?
例如,这些条件是否保证在擦除后保持,这意味着erase()
迭代器后的所有元素都向左移1:
vec[0] == 15
vec[1] == 20
或者允许实现在他们认为合适时移动值,从而创建vec[0] == 20
等场景?
我想引用该标准的相关部分。
答案 0 :(得分:13)
让我们从头开始:
23.2.3序列容器
序列容器将所有相同类型的有限对象组织成严格的线性排列。 该库提供了四种基本类型的序列容器:vector, forward_list,list和deque。
强调“严格的线性安排”。这是明确的。
这个定义之后是一个名为“序列容器需求”的表,它因此描述了erase()
:
a.erase(q) [ ... ] Effects: Erases the element pointed to by q
结合起来,这没有留下解释的余地。向量中的元素总是处于“严格的线性排列”中,因此当其中一个元素为erase()
d时,只有一个可能的结果。
答案 1 :(得分:7)
从技术上讲,不,该标准没有写出一个承诺,即你不会在最不期望的时候重新订购元素。
实际上,显然它不会那样做。那太荒谬了。
从法律上讲,你可以采用“效果”条款:
除非另有说明,否则删除 q
指向的元素
没有其他效果(例如迭代器失效,从擦除效果开始)。
答案 2 :(得分:4)
我发现我发现的两个陈述保证会是:
C ++ 11标准
<强> 23.2.1 强> 11 除非另有说明(显式或通过根据其他函数定义函数),调用容器成员函数或将容器作为参数传递给库函数不应使迭代器无效或更改该容器中对象的值。
如果你不能“更改”的值,那么就不能随意重新排序元素(比如用删除的元素交换结束值)。
<强> 23.2.3 强> 12 从a.erase(q)返回的迭代器指向元素被删除之前紧跟q之后的元素。如果不存在这样的元素,则返回a.end()。
这意味着元素的概念擦除是通过从右边缩小物理差距来实现的。鉴于以前的规则,概念上缩小差距,不能被视为概念更改其价值。这意味着唯一的实现将按顺序移动值。
通过解释。
标准正在处理抽象的概念而不是实际的实现,尽管它的语句会影响实现。
概念上擦除元素只是删除它而已。所以给出了序列:
3 5 7 4 2 9 (6 values)
如果我们删除第3个元素概念给我们什么?
3 5 4 2 9 (5 values)
由于上面的第一个陈述,这一定是真的:
<强> 23.2.1 强> 11 除非另有说明(显式或通过根据其他函数定义函数),调用容器成员函数或将容器作为参数传递给库函数不应使迭代器无效或更改该容器中对象的值。
如果实现重新排序了这些元素,比如将删除的元素与结束元素交换,那么规则就会被破坏,因为我们最终会这样做:
3 5 9 4 2
从概念上讲,擦除元素右侧的结果值已从4变为9,从而违反了规则。