简体   繁体   English

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

[英]Why std::vector iterator is invalidated after the erase() call?

The C++ reference clearly state that calling std::vector::erase(it) on iterator will invalidate all iterators pointing to and after the erased element. C ++参考明确指出,在迭代器上调用std::vector::erase(it) 将使所有指向已删除元素及其后的迭代器无效 http://en.cppreference.com/w/cpp/container/vector/erase http://en.cppreference.com/w/cpp/container/vector/erase

I do understand why such iterators became non-dereferenceable after the erase call, but i am curious why they need to became invalid, what implementation details require it? 我确实理解为什么在erase调用之后,此类迭代器变得不可取消引用,但是我很好奇为什么它们需要变得无效,请问有哪些实现细节?

For instance standard says that std::vector must be implemented with elements stored contiguously and that elements can be accessed not only through iterators, but also using offsets on regular pointers to elements so it seems logical that iterators for such container will probably be implemented as pointers - but then how pointers could became invalidated? 例如,标准说std::vector必须使用连续存储的元素来实现,并且elements can be accessed not only through iterators, but also using offsets on regular pointers to elements因此逻辑上可以将此类容器的迭代器实现为指针-但是指针如何变得无效?

One of the principles on which the conceptual idea of iterator is built, is as follows: as long as iterator remains non-aliased, dereferenceable and non-modified, it should refer to the same entity. 构建迭代器概念概念的原则之一如下:只要迭代器保持非混淆,可引用和不可修改,它就应该引用同一实体。 In other words, dereferencing the same iterator multiple times should yield the same value. 换句话说,多次取消引用相同的迭代器应产生相同的值。 Algorithms that use iterators may rely on that. 使用迭代器的算法可能依赖于此。

What you proposing would result in an iterator that would "magically" change the value it refers to even though the iterator itself remains unchanged. 您提议的结果将导致迭代器“神奇地”更改其引用的值,即使迭代器本身保持不变。 This is not acceptable within the conceptual idea of iterator. 在迭代器的概念范围内,这是不可接受的。


On the second thought, what I said above is obviously flawed in a sense that we can always apply some modifying operation to the vector that shifts elements around (eg std::random_shuffle ). 第二种想法,我上面所说的显然是有缺陷的,因为我们总是可以对向量进行一些修改操作以使元素四处移动(例如std::random_shuffle )。 Such operation would not invalidate any iterators, but would easily change the values the iterators refer to. 这样的操作不会使任何迭代器无效,但会轻易更改迭代器引用的值。 How is that different from element shifting triggered by erase ? 这与erase触发的元素移位有何不同? It isn't. 不是。

"invalidated" can mean "no longer points to what it used to", not just "may not point to any valid element" “无效”可以表示“不再指向过去使用的内容”,而不仅仅是“可能不指向任何有效元素”

consider (uncompiled code): 考虑(未编译的代码):

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());

At this point, iter has been invalidated. 此时, iter已失效。 It no longer "points to" the same element that it did before. 它不再“指向”以前的相同元素。

std::vector must be implemented with elements stored contiguously std :: vector必须使用连续存储的元素来实现

This is the reason. 这就是原因。 If you erase an element inside the vector, the elements, at the least, must be shifted. 如果删除向量中的一个元素,则至少必须移动这些元素。 You could, not with debug protection: 您可以,但不能使用调试保护:

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

And it will likely print '4'. 并且可能会打印“ 4”。 But there is no guaranty. 但是没有任何保证。 What if the vector reallocs? 如果向量重新分配怎么办? What if you erase test.begin( ) + 6 ? 如果删除test.begin( ) + 6怎么办? If you change the size of a vector, it can be moved. 如果更改矢量的大小,则可以移动它。

More Info 更多信息

I simply see no reason for the iterators to become invalid with the point where I begin to erase the elements. 我只是简单地看到没有理由让迭代器在开始删除元素时变得无效。 vector::erase( ... ) does use the assignment-opetor, so the objects in the vector are never invalidated. vector :: erase(...)确实使用赋值操作符,因此vector中的对象永远不会失效。 If I would do the same with my own code ... 如果我用自己的代码做同样的事情...

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() );
}

... the iterators would be valid until the point where I cut the vector. ...迭代器将一直有效,直到我切下矢量为止。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM