opetroch
opetroch

Reputation: 4095

Is it valid to call operator-- for an iterator when it points to std::begin()

Is it valid to call operator-- on an iterator that already points to the first element of the collection? Does the answer change for different collections (e.g. list vs vector vs set). E.g. see below

#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
 
int main()
{
    std::vector<int> v {1, 2, 4, 8, 16};

    auto i=v.begin();
    auto j=i;
    --i;  // not sure what's the effect of this
    v.erase(j);
    ++i;  // also not sure if this is not std::begin() anymore, what's the effect of ++
    v.erase(i);

 
    // Print vector.
    std::for_each(v.begin(), v.end(), [](const int n) { std::cout << n << ' '; });
}

I suspect it's undefined behaviour but not quite sure.

Furthermore, what about removing elements from a std::list like below

    std::list<int> v = { 1, 2, 3, 4, 5, 6 };
 
    for (auto it = v.begin(); it != v.end(); it++)
    {
        v.erase(it--);
    }

Upvotes: 2

Views: 240

Answers (1)

Nathan Pierson
Nathan Pierson

Reputation: 5565

Let's take std::list as an example, because essentially the same reasoning will apply to the other containers.

Looking at the member types of std::list, we see that std::list::iterator is a LegacyBidirectionalIterator. Checking the description there, we see the following precondition listed for operator-- to be valid:

Preconditions:

  • a is decrementable (there exists such b that a == ++b)

This is not the case for an iterator to the first element in a container, and indeed cppreference explicitly calls this out:

The begin iterator is not decrementable and the behavior is undefined if --container.begin() is evaluated.

Other containers like std::vector use more expansive notions like LegacyRandomAccessIterator, but there's nothing there that changes the behavior of decrementing a begin iterator.

Upvotes: 3

Related Questions