简体   繁体   English

为什么std :: vector :: insert会在插入点之后使所有迭代器无效

[英]Why does std::vector::insert invalidate all iterators after the insertion point

When insert -ing into a std::vector the C++ standard assures that all iterators before the insertion point remain valid as long as the capacity is not exhausted (see [23.2.4.3/1] or std::vector iterator invalidation ). insertstd::vector ,C ++标准确保插入点之前的所有迭代器保持有效,只要capacity没有用完(参见[23.2.4.3/1]或std :: vector iterator invalidation )。

What is the rationale behind not allowing iterators after the insertion point to remain valid (if the capacity is not exhausted)? 在插入点保持有效(如果容量没有用尽)之后不允许迭代器的原因是什么? Of course, they would then point to a different element but (from the presumed implementation of std::vector ) it should still be possible to use such an iterator (for example dereference it or increment it). 当然,然后他们会指向一个不同的元素,但是(从std::vector的假定实现),仍然可以使用这样的迭代器(例如取消引用它或递增它)。

You seem to be thinking of an "invalid" iterator as only one that would provoke a crash if used, but the standard's definition is broader. 您似乎在想一个“无效”迭代器,因为只有一个会在使用时引发崩溃,但标准的定义更广泛。 It includes the possibility that the iterator can still safely be dereferenced, but no longer points to the element it is expected to point to. 它包括迭代器仍然可以安全地解除引用的可能性,但不再指向它预期指向的元素。 (This is a special case of the observation that "undefined behavior" does not mean "your program will immediately crash"; it can also mean "your program will silently compute the wrong result" or even "nothing observably wrong will occur on this implementation.") (这是观察的特殊情况,“未定义的行为” 并不意味着“您的程序将立即崩溃”;它也可能意味着“您的程序将默默地计算错误的结果”,甚至“在实现中不会发生任何明显的错误” “。)

It is easier to demonstrate why this is an issue with erase : 更容易证明为什么这是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';
}

On typical implementations of C++ this program will not crash, but it will print 0 1 2 3 4 6 , rather than 0 1 2 3 6 as probably intended, because erasing the first 4 invalidated p -- by advancing it over the second 4 . 在C ++的典型实现中,这个程序不会崩溃,但它会打印0 1 2 3 4 6 ,而不是0 1 2 3 6 ,因为可能会打算删除前4 无效的 p - 通过在第二个4推进它。

Your C++ implementation may have a special "debugging" mode in which this program does crash when run. 您的C ++实现可能有一个特殊的“调试”模式,在该模式下,该程序在运行时崩溃。 For instance, with GCC 4.8: 例如,使用GCC 4.8:

$ g++ -std=c++11 -W -Wall test.cc && ./a.out
 0 1 2 3 4 6

but

$ 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

Do understand that the program provokes undefined behavior either way . 请理解该程序无论如何都会引发未定义的行为。 It is just that the consequences of the undefined behavior are more dramatic in the debugging mode. 只是在调试模式下,未定义行为的后果更为显着。

A vector grows dynamically, so when you push onto a vector, if there is no space for the item, memory needs to be allocated for it. 向量会动态增长,因此当您按下向量时,如果项目没有空间,则需要为其分配内存。 The Standard mandates that vector must store its elements in contiguous memory, so when memory is allocate, it has to be enough to store ALL the existing elements, plus the new one. 标准要求vector必须将其元素存储在连续的内存中,因此在分配内存时,必须足以存储所有现有元素和新元素。

The vector doesn't know about any iterators for itself, so cannot update them into the new storage of elements. 向量不知道自身的任何迭代器,因此无法将它们更新为新的元素存储。 Iterators are therefore invalid after the memory has been reallocated. 因此,在重新分配内存后,迭代器无效。

That the iterators may refer to a different element is enough for them to be invalidated. 迭代器可能引用不同的元素就足以使它们失效。 An iterator is supposed to refer to the same element for the duration of its valid lifetime. 迭代器应该在其有效生命周期的持续时间内引用相同的元素。

You're right that, in practice, you may not experience any crashing or nasal demons if you were to dereference such an iterator, but that does not make it valid. 你是对的,在实践中,如果你要取消引用这样的迭代器,你可能不会遇到任何崩溃或鼻子恶魔,但这并不能使它有效。

The vector does not know which iterators exist. 向量不知道哪些迭代器存在。 Yet the memory location of the elements after the inserted element changed. 然而,插入元素后元素的内存位置发生了变化。 This means, the iterators need to be updated to reflect that change should they remain valid. 这意味着,需要更新迭代器以反映它们保持有效的更改。 But the vector cannot do this update, because it does not know which iterators exist. 但是向量无法执行此更新,因为它不知道存在哪些迭代器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 pop_back() 真的会使 std::vector 上的 *all* 迭代器无效吗? - Does pop_back() really invalidate *all* iterators on an std::vector? std :: vector :: swap会使迭代器失效吗? - Does std::vector::swap invalidate iterators? std :: unique是否会使向量迭代器无效? - Does std::unique invalidate vector iterators? 如果向量有足够的空间(通过储备创建),std :: vector :: insert()是否会使迭代器无效? - Does std::vector::insert() invalidate iterators if the vector has enough room (created through reserve)? 带有状态分配器的 std::vector::swap() 是否应该使所有迭代器无效? - Should std::vector::swap() with stateful allocators invalidate all iterators? std :: vector :: reserve是否保证在这种情况下实现不会使迭代器失效? - Does std::vector::reserve guarantee that the implementation will not invalidate iterators in this case? 移动向量会使迭代器无效吗? - Does moving a vector invalidate iterators? 调整向量大小会使迭代器无效吗? - Does resizing a vector invalidate iterators? 向量排序是否使迭代器无效? - Does a vector sort invalidate iterators? std :: deque:“插入和删除元素可能使迭代器无效”是什么意思? - std::deque : What does “insertion and deletion of elements may invalidate iterators” mean?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM