移动向量是否会使迭代器无效?

2022-01-10 00:00:00 iterator c++ c++11

如果我有一个指向向量 a 的迭代器,那么我从 a 移动构造或移动分配向量 b,该迭代器是否仍然指向同一个元素(现在在向量 b 中)?这就是我在代码中的意思:

If I have an iterator into vector a, then I move-construct or move-assign vector b from a, does that iterator still point to the same element (now in vector b)? Here's what I mean in code:

#include <vector>
#include <iostream>

int main(int argc, char *argv[])
{
    std::vector<int>::iterator a_iter;
    std::vector<int> b;
    {
        std::vector<int> a{1, 2, 3, 4, 5};
        a_iter = a.begin() + 2;
        b = std::move(a);
    }
    std::cout << *a_iter << std::endl; // Is a_iter valid here?
    return 0;
}

a_iter 是否仍然有效,因为 a 已被移动到 b 中,还是迭代器因移动而失效?作为参考,std::vector::swap 不会使迭代器失效.

Is a_iter still valid since a has been moved into b, or is the iterator invalidated by the move? For reference, std::vector::swap does not invalidate iterators.

推荐答案

虽然假设 iteratormove 之后仍然有效可能是合理的,但我不认为'认为标准实际上不能保证这一点.因此,迭代器在 move 之后处于未定义状态.

While it might be reasonable to assume that iterators are still valid after a move, I don't think the Standard actually guarantees this. Therefore, the iterators are in an undefined state after the move.

我在标准中找不到任何参考明确指出在 move 之前存在的迭代器仍然有效在 代码>移动.

There is no reference I can find in the Standard which specifically states that iterators that existed before a move are still valid after the move.

从表面上看,假设 iterator通常被实现为指向受控序列的指针似乎是完全合理的.如果是这种情况,那么迭代器在 move 之后仍然有效.

On the surface, it would seem to be perfectly reasonable to assume that an iterator is typically implemented as pointers in to the controlled sequence. If that's the case, then the iterators would still be valid after the move.

但是 iterator 的实现是实现定义的.这意味着,只要特定平台上的 iterator 满足标准规定的要求,它就可以以任何方式实现.理论上,它可以实现为返回 vector 类的指针和索引的组合.如果是,那么move之后迭代器就会失效.

But the implementation of an iterator is implementation-defined. Meaning, so long as the iterator on a particular platform meets the requirements set forth by the Standard, it can be implemented in any way whatsoever. It could, in theory, be implemented as a combination of a pointer back to the vector class along with an index. If that's the case, then the iterators would become invalid after the move.

iterator 是否以这种方式实际实现无关紧要.它可以以这种方式实现,因此如果没有标准的特定保证后 move 迭代器仍然有效,您不能假设它们是有效的.还要记住,在 swap 之后 对迭代器有这样的保证.这在之前的标准中得到了明确的说明.也许这只是标准委员会的疏忽,没有在 move 之后对迭代器做出类似的澄清,但无论如何都没有这样的保证.

Whether or not an iterator is actually implemented this way is irrelevant. It could be implemented this way, so without a specific guarantee from the Standard that post-move iterators are still valid, you cannot assume that they are. Bear in mind also that there is such a guarantee for iterators after a swap. This was specifically clarified from the previous Standard. Perhaps it was simply an oversight of the Std comittee to not make a similar clarification for iterators after a move, but in any case there is no such guarantee.

因此,总而言之,您不能假设您的迭代器在 move 之后仍然很好.

Therefore, the long and the short of it is you can't assume your iterators are still good after a move.

n3242 草案中的 23.2.1/11 指出:

23.2.1/11 in Draft n3242 states that:

除非另有说明(明确或通过定义其他功能的功能),调用容器成员函数或将容器作为参数传递给库函数不应使对象的迭代器无效或更改其值在那个容器内.

Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.

这可能会导致人们得出结论,迭代器在 move 之后是有效的,但我不同意.在您的示例代码中,a_itervector a 的迭代器.在 move 之后,那个容器 a 肯定已经改变了.我的结论是上述条款不适用于这种情况.

This might lead one to conclude that the iterators are valid after a move, but I disagree. In your example code, a_iter was an iterator in to the vector a. After the move, that container, a has certainly been changed. My conclusion is the above clause does not apply in this case.

相关文章