0

How do I get an iterator to the next-to-last element in a STL list without creating a temporary and modifying the list? Is it possible to just say: --(--mylist.end())? Or would this change the end iterator of the list due to the prefix decrement?

ritter
  • 7,447
  • 7
  • 51
  • 84
  • 1
    You might want to look at this: http://stackoverflow.com/questions/5322104/how-portable-is-end-iterator-decrement – filmor Jul 12 '12 at 10:16

3 Answers3

3

Please note that in general, --mylist.end() is not guaranteed to compile for every container.

For example, if you use a std::vector or std::array in release mode, mylist.end() is probably a raw pointer, and you cannot decrement a pointer returned by value from a function.

A generic solution to this problem in C++11 is std::prev(std::prev(mylist.end())), after checking that the list is long enough, of course. You need to #include <iterator> for this.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Interesting. But why can't i decrement a pointer returned by value. That's exactly why it doesn't change the `end` iterator itself, due to returning by value – ritter Jul 12 '12 at 10:27
  • Because a call to a function that returns by value is an rvalue, but the `--` operator for scalars (such as ints or raw pointers) requires an lvalue. Just try `--new T();` and you will get a compiler error saying "lvalue required as decrement operand" or something like that. On the other hand, it is perfectly fine to call operator `--` on a temporary object, as long as it is implemented as a member function. In practice, it won't work for *postfix* `--`, because that one is usually implemented as a free function (in terms of prefix `--`, to avoid code duplication), not as a member function. – fredoverflow Jul 12 '12 at 10:32
  • Can you replace "std::prev(std::prev(mylist.end()))" with just "end()-2" for containers with bidirectional iterators like vector ? – Razzle Aug 13 '21 at 16:07
3

You could use std::advance and a reverse_iterator:

SomeContainerType::reverse_iterator it = myList.rbegin();
std::advance(it, 1); // next to last element

This works even if the iterator type in question does not support operator+.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
2

if okay with a reverse_iterator, then: some_list.rbegin() + 1;

Nim
  • 33,299
  • 2
  • 62
  • 101
  • 1
    Assuming `some_list` is a `std::list` the iterator will not support `operator+` – pmr Jul 12 '12 at 10:28
  • 1
    std::list supports bidirectional iterators; as Nim says, just call method rbegin() and take the following elements with operator++ – Bentoy13 Jul 12 '12 at 10:42