当insert
进入std::vector
C ++标准时,只要capacity
没有用尽,插入点之前的所有迭代器都会保持有效(参见[23.2.4.3/] 1]或std::vector iterator invalidation)。
在插入点保持有效(如果容量没有用尽)后不允许迭代器的原因是什么?当然,他们会指向一个不同的元素,但是(从std::vector
的假设实现),仍然可以使用这样的迭代器(例如取消引用它或增加它)。
答案 0 :(得分:9)
你似乎在考虑一个“无效”的迭代器,因为它只会在使用时引发崩溃,但标准的定义更广泛。它包括迭代器仍然可以安全地解除引用的可能性,但不再指向它预期指向的元素。 (这是观察的特殊情况,“未定义的行为”不意味着“您的程序将立即崩溃”;它也可能意味着“您的程序将默默地计算错误的结果”甚至“没有” 此实现会发生明显错误。“)
更容易证明为什么这是erase
的问题:
#include <vector>
#include <iostream>
int main(void)
{
std::vector<int> a { 0, 1, 2, 3, 4, 4, 6 };
for (auto p = a.begin(); p != a.end(); p++) // THIS IS WRONG
if (*p == 4)
a.erase(p);
for (auto p = a.begin(); p != a.end(); p++)
std::cout << ' ' << *p;
std::cout << '\n';
}
在C ++的典型实现中,此程序不会崩溃,但它会打印0 1 2 3 4 6
,而不是0 1 2 3 6
,因为删除了第一个4
无效 p
- 通过推进第二个4
。
您的C ++实现可能有一种特殊的“调试”模式,运行时该程序 会崩溃。例如,GCC 4.8:
$ g++ -std=c++11 -W -Wall test.cc && ./a.out
0 1 2 3 4 6
但
$ g++ -std=c++11 -W -Wall -D_GLIBCXX_DEBUG test.cc && ./a.out
/usr/include/c++/4.8/debug/safe_iterator.h:307:error: attempt to increment
a singular iterator.
Objects involved in the operation:
iterator "this" @ 0x0x7fff5d659470 {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiNSt9__cxx19986vectorIiSaIiEEEEENSt7__debug6vectorIiS6_EEEE (mutable iterator);
state = singular;
references sequence with type `NSt7__debug6vectorIiSaIiEEE' @ 0x0x7fff5d659470
}
Aborted
请理解该程序以任何方式引发未定义的行为 。只是在调试模式下未定义行为的后果更为显着。
答案 1 :(得分:3)
矢量会动态增长,因此当您按下矢量时,如果项目没有空间,则需要为其分配内存。标准规定vector
必须将其元素存储在连续的内存中,因此在分配内存时,必须足以存储所有现有元素,再加上新元素。
向量不知道自身的任何迭代器,因此无法将它们更新为新的元素存储。因此,在重新分配内存后,迭代器无效。
答案 2 :(得分:1)
向量不知道哪些迭代器存在。然而,插入元素后元素的内存位置发生了变化。这意味着,需要更新迭代器以反映它们保持有效的更改。但是向量无法执行此更新,因为它不知道存在哪些迭代器。