Search code examples
c++pointersiteratorundefined-behaviorpointer-arithmetic

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?


Solution

  • 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.