Assignment (operator =) invalidates iterators for containers

泪湿孤枕 提交于 2019-12-11 13:14:59

问题


I have a code just like this:

std::vector<int> v1 = { 1, 2, 3, 4 };  
std::vector<int> v2 = { 7, 8, 9, 10 };  
std::vector<int>::iterator it = std::next(v1.begin());  
v1 = v2;  
int test = *it;  
std::cout << test;   

The above code will throw an error: iterator not dereferencable.

However, if I replace vector with list as follows:

std::list<int> v1 = { 1, 2, 3, 4 };  
std::list<int> v2 = { 7, 8, 9, 10 };  
std::list<int>::iterator it = std::next(v1.begin());  
v1 = v2;  
int test = *it;  
std::cout << test;   

The code just ran as expected without error.
From Iterator invalidation rules, and the std::list::operator=, I was told that after the call to operator =, all iterators, references and pointers related to this container are invalidated, except the end iterators. But why the above code with std::list works? Did I misunderstand something essential?


回答1:


When an iterator is invalidated, dereferencing it is undefined behavior. Therefore, whatever behavior you observed in doing so is irrelevant, as far as the spec is concerned. "Working", according to your expectations, is among the allowable behaviors.

FWIW (not much, tbh), I would expect the std::list assignment operator to be implemented equivalent to something like this:

list& operator=(list const& rhs) {
    if (this == &rhs)
        return *this;

    auto lhs_i = begin();
    auto rhs_i = rhs.begin();

    // write over the elements in any currently existing nodes, this
    // avoids any unnecessary allocations
    while (lhs_i != end() && rhs_i != rhs.end()) {
        *lhs_i++ = *rhs_i++;
    }

    // erase any extra elements if size() > rhs.size()
    erase(lhs_i, end());

    // push back additional elements if size() < rhs.size()
    while (rhs_i != rhs.end()) {
        push_back(*rhs_i++);
    }

    return *this;
}

And if it is, you can see that, for a case such as yours, where the lists both have the same number of elements, no elements are created or destroyed, and so you would very much expect iterators to go on working exactly as normal. This is, of course, entirely speculation, and definitely not behavior which you should rely on because even if it is the case for your implementation, they can change it on the next release without notice.




回答2:


It is undefined behavior but GCC has debug containers to catch this kind of behavior.

Enable it with -D_GLIBCXX_DEBUG:

     int test = *it;
         ^~~~
/usr/local/include/c++/6.1.0/debug/safe_iterator.h:270:

Error: attempt to dereference a singular iterator.

Objects involved in the operation:

    iterator "this" @ 0x0x7fff5f561e90 {
      type = __gnu_debug::_Safe_iterator<std::__cxx1998::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator);
      state = singular;
      references sequence with type 'std::__debug::list<int, std::allocator<int> >' @ 0x0x7fff5f561ef0
    }
bash: line 7: 16071 Aborted                 (core dumped) ./a.out


来源:https://stackoverflow.com/questions/37505457/assignment-operator-invalidates-iterators-for-containers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!