Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subtracting 1 vs decrementing an iterator

In the accepted answer to "Iterator to last element of std::vector using end()--" @barry states:

Note that if vector::iterator is just T* (which would be valid), the first form above is ill-formed. The second two work regardless, so are preferable.

referring to his code:

std::vector<int>::iterator it = --container.end();
std::vector<int>::iterator it = container.end() - 1;
std::vector<int>::iterator it = std::prev(container.end());

This opinion is disputed in the comments, however without a clear resolution. So that's my question: what exactly is the semantic difference between the first and the second? And would the answer be different for iterators over structures other than vector?

like image 843
ByteEater Avatar asked Oct 04 '21 22:10

ByteEater


People also ask

Can we subtract two iterators?

std::vector<T>::iterator satisfies the RandomAccessIterator concept, which means that it has an operator- that allows you to subtract two iterators and obtain a std::vector<T>::iterator::difference_type that indicates the distance between the two iterators.

What happens when you dereference an iterator?

3. Dereferencing: An input iterator can be dereferenced, using the operator * and -> as an rvalue to obtain the value stored at the position being pointed to by the iterator. 4. Incrementable: An input iterator can be incremented, so that it refers to the next element in the sequence, using operator ++().

How do you decrement an iterator?

The random access iterator can be decremented either by using the decrement operator(- -) or by using arithmetic operation. If itr is an iterator. We can use itr – – or – – itr for decrementing it. As it is a random access iterator we can also use arithmetic operation such as itr=itr-1 for decrementing it.

Can you decrement iterator end?

It appears that you can still decrement the iterator returned from end() and dereference the decremented iterator, as long as it's not a temporary.


Video Answer


1 Answers

For any standard library container, the member function end() returns an r-value. It's a "temporary" until you assign it to a variable.

The decrement operator -- is not required to work on r-value iterators. You would be modifying a temporary, which C++ historically has taken measures to avoid.

Therefore, --container.end() might compile on your standard-conforming C++compiler. But it might not.

std::prev(container.end()) will work on every standard-conforming compiler.


To review:

  • --container.end() may not compile. It is up to the implementation.
  • container.end() - 1 will only compile if the container uses random-access iterators.
  • std::prev(container.end()) will always compile.

All three forms will produce the same result, if they compile.

like image 190
Drew Dormann Avatar answered Oct 20 '22 04:10

Drew Dormann