为什么在erase()调用后std :: vector迭代器无效?

时间:2016-11-30 22:43:40

标签: c++ c++11 vector stl iterator

C ++参考清楚地说明在迭代器上调用MsgBox (CreateObject("WScript.Shell").Exec("bash -c ""ls""").StdOut.ReadAll) 使指向擦除元素的所有迭代器无效。 http://en.cppreference.com/w/cpp/container/vector/erase

我确实理解为什么在std::vector::erase(it)调用之后这些迭代器变得不可解除引用,但我很好奇为什么它们需要变得无效,实现细节需要什么呢?

例如标准说erase必须用连续存储的元素和std::vector实现,所以这个容器的迭代器可能会被实现为指针似乎是合乎逻辑的 - 但是指针如何变得无效?

4 个答案:

答案 0 :(得分:7)

构建 iterator 的概念性思想的原则之一如下:只要迭代器仍然是非别名,可解除引用和未修改的,它应该引用相同的实体。换句话说,多次取消引用相同的迭代器应该产生相同的值。使用迭代器的算法可能依赖于此。

你提出的建议会导致一个神奇的迭代器#34;即使迭代器本身保持不变,也要更改它引用的值。这在迭代器的概念思想中是不可接受的。

在第二个想法中,我上面所说的显然是有缺陷的,因为我们总是可以对向量移动元素的向量应用一些修改操作(例如std::random_shuffle)。这样的操作不会使任何迭代器无效,但很容易改变迭代器引用的值。这与erase触发的元素转移有什么不同?它不是。

答案 1 :(得分:4)

“无效”可能意味着“不再指向它曾经用过的东西”,而不仅仅是“可能没有指向任何有效元素”

考虑(未编译的代码):

vector<int> v = {0, 1, 2, 3, 4, 5};
vector<int>::iterator iter = v.begin() + 3;  // "points to" 3
assert(*iter == 3);
v.erase(v.begin());

此时,iter已失效。它不再“指向”它之前所做的相同元素。

答案 2 :(得分:2)

  必须使用连续存储的元素实现

std :: vector

这就是原因。如果擦除向量内的元素,则必须至少移动元素。你可以,而不是调试保护:

std::vector< int > test= {1,2,3,4,5,6,7};
auto it= test.begin( ) + 2;
test.erase( it );
std::cout << *it << std::endl;

它可能会印刷&#4;&#39;。但是没有保证。如果向量重新分配怎么办?如果您删除test.begin( ) + 6怎么办?如果更改矢量的大小,则可以移动它。

More Info

答案 3 :(得分:0)

我只是简单地看到没有理由让迭代器在开始删除元素时变得无效。 vector :: erase(...)确实使用赋值操作符,因此vector中的对象永远不会失效。如果我用自己的代码做同样的事情...

template<typename T>
void vector_erase( vector<T> &v, typename vector<T>::iterator first, typename vector<T>::iterator last )
{
    typename vector<T>::iterator shiftOld,
                                 shiftNew;
    for( shiftOld = last, shiftNew = first; shiftOld != v.end(); ++shiftOld, ++shiftNew )
        *shiftNew = move( *shiftOld );
    v.resize( shiftNew - v.begin() );
}

...迭代器将一直有效,直到我剪切矢量为止。