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
实现,所以这个容器的迭代器可能会被实现为指针似乎是合乎逻辑的 - 但是指针如何变得无效?
答案 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
怎么办?如果更改矢量的大小,则可以移动它。
答案 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() );
}
...迭代器将一直有效,直到我剪切矢量为止。