Search code examples
c++c++11iteratorstdlist

Validity of std::prev and std::next for std::list


I am storing an iterator to a list:

list<int> l;
l.push_back(21); l.push_back(1); l.push_back(31); l.push_back(41);

auto it = l.find(21);

In my algorithm, whenever I delete a node, I need to add up the adjoining elements. Something like this:

auto prev = std::prev(it);
auto next = std::next(it);
*prev = *prev + *next;
l.erase(it);

As you see, I need to ensure all boundary conditions. What values do std::prev() and std::next() return if:

  • they are the first and last elements;
  • or if it itself has become invalid at some point?

Solution

  • What values do std::prev() and std::next() return...

    They return the nth (where n defaults to 1) predecessor or successor of the iterator it. See here for [iterator.operations] /6 and /7.

    ... if they are the first and last elements; or if it itself has become invalid at some point?

    The iterator needs to be valid before the call is made. The return value would be an invalid iterator if it is one of the corresponding boundary iterators; i.e. it == begin() for prev(it) and it == end() for next(it).

    The validity of it needs to be established before it is used as an argument to prev() or next(). std::prev() and std::next() have no why of determining if the iterator decrement or increment would put the iterator outside the bounds of the container.

    As such, it sounds like you would need to code for two boundary conditions in the erase part of the algorithm; first where it == l.begin() and second where it == prev(l.end()), and possibly a third if the element is not found (hence it == l.end()).

    // only proceed it something is found...
    if (it != l.end()) {
      if (it == l.begin()) {
        // nothing to do...? element removed is the first one
      }
      else if (it == std::prev(l.end()) {
        // nothing? element removed is the last one....
      }
      else {
        auto prev = std::prev(it);
        auto next = std::next(it);
        *prev = *prev + *next;
      }
      l.erase(it); // remove the found element...
    }