Increment / Decrease Vector Iterator

Nikolay Josuttis "C ++ Standard Library"

Chapter 9: The STL iterator states:

The following may not compile on any platform:

std::vector <int> coll; //sort, starting with second element //- NONPORTABLE version if (coll.size() > 1){ std::sort(++coll.begin(),col.end()); } 

Depending on the platform, compiling ++ col.begin () may fail. However, if you use, for example, deque rather than a vector, compilation always succeeds ....... the functions of the utility next () and prev () are provided with C ++ 11, so consider code portability.

Can someone explain this behavior?

I have the correct output for MINGW gcc 4.6.1, Windows OS:

 std::vector<int> coll ; for (int i=15; i>=1; i--) coll.push_back(i); sort(++coll.begin(),coll.end()); 
+4
source share
3 answers

The cause of this potential problem is well explained by Josuttis:

The reason for this strange problem is that iterators of array s and string vectors can be implemented as regular pointers. And for all basic data types, such as pointers, you are not allowed to change temporary values. However, for structures and classes this is allowed.

In other words, it all depends on whether std::vector<int>::iterator defined as a class or just a typedef for a int* . Any of them is allowed by the standard, so it can cause a problem for some compilers, but not for others.

When you call coll.begin() , an rvalue std::vector<int>::iterator . If std::vector<int>::iterator is a class with the operator++ prefix embedded, then the rvalue modification is allowed and therefore will be compiled. However, it std::vector<int>::iterator is a typedef for a pointer to an int, it is an rvalue of a fundamental type and therefore cannot compile.

+3
source

Josuttis is technically wrong with ++container.begin() always defined behavior when container is std::deque : the standard does not guarantee that container.begin() returns a mutable lvalue for any type of container. When he says that “he always succeeds”, that he really means “on every realization that I know, she succeeds”, which is not exactly the same thing.

In fairness, before C ++ 11 it is impossible for an object of type const of class type to restrict its operations to lvalues, but do not be surprised if you start to see classes in the near future, t allows you to assign, increase and decrease the values ​​of r for consistency with the main types.

+1
source

You can do ++ by the return value of vector::begin() if it returns the value l - essentially the type of object that has an overloaded ++ operator . I do not think that the standard insists on how to implement vector::iterator . The corresponding C ++ standard library can implement vector::iterator as a pointer, that is, for vector<T> , vector<T>::iterator can be T* , in which case the ++ operation will not compile, because the return is value of r, and you cannot increase the value of r.

The C ++ library that you are using currently implements vector::iterator as an object with overloaded ++ and therefore it works. But this does not mean that it is tolerated.

Try this program

 class iter { int * p_; public: iter(int * p):p_(p) {} iter & operator ++() { ++p_; return *this; } }; class A { int * p_; public: typedef int * iterator; typedef iter miterator; iterator get() { return p_; } miterator ret() { return miterator(p_); } }; int main(int argc, char **argv) { A a; ++a.get(); // Doesn't compile A::iterator i = a.get(); ++i; // compiles ++a.ret(); //compiles } 
0
source

Source: https://habr.com/ru/post/1492483/


All Articles