What's the difference between std::advance and std::next?
Asked Answered
A

4

81

Is there more beyond advance takes negative numbers?

Arapaho answered 22/2, 2013 at 4:50 Comment(0)
L
121

std::advance

  • modifies its argument
  • returns nothing
  • works on input iterators or better (or bi-directional iterators if a negative distance is given)

std::next

  • leaves its argument unmodified
  • returns a copy of the argument, advanced by the specified amount
  • works on forward iterators or better (or bi-directional iterators if a negative distance is given))
Leahy answered 22/2, 2013 at 4:54 Comment(4)
I don't suppose you happen to know why they made it UB to use next on an input iterator that's not a forward iterator, even though the defined effect of next is guaranteed to work on an input iterator?Slippy
@HowardHinnant: gah, thanks. So basically if you're working with an InputIterator then you should just use ++ (or advance, to protect yourself from the devastating convenience of one-liners involving next), or write your own my_next that quite possibly is identical to your implementation's std::next, maybe with a traits assertion removed. It occurs to me that on the same argument, InputIterator shouldn't require operator++(int). Way too late to fix that now, I suppose.Slippy
If I had a time machine I would take away InputIterator's copy constructor and make it move-only. I think that would make them much safer and easier to reason about.Ariellearies
The extra constraint on std::next was backed out by cplusplus.github.io/LWG/lwg-defects.html#2353Min
S
21

Perhaps the biggest practical difference is that std::next() is only available from C++11.

std::next() will advance by one by default, whereas std::advance() requires a distance.

And then there are the return values:

std::next() takes negative numbers just like std::advance, and in that case requires that the iterator must be bidirectional. std::prev() would be more readable when the intent is specifically to move backwards.

Seldun answered 22/2, 2013 at 4:54 Comment(4)
next doesn't only move forwards, it's like advance in that respect. Given the existence of prev it might be strange to write next(it, -1), with a negated literal. But for iterators of the right categories it's fine for example to write next(it, distance(it2, it3)) even if it2 > it3.Slippy
@SteveJessop: Thanks for the edit and for preserving the emphasis on readability.Seldun
@Johnsyweb std::next() is available after C++11, not only in C++11.Decreasing
Thanks @John. The answer was correct when I wrote it nine years ago.Seldun
S
7

std::advance

The function advance() increments the position of an iterator passed as the argument. Thus, the function lets the iterator step forward (or backward) more than one element:

#include <iterator>
void advance (InputIterator& pos, Dist n)
  • Lets the input iterator pos step n elements forward (or backward).
  • For bidirectional and random-access iterators, n may be negative to step backward.
  • Dist is a template type. Normally, it must be an integral type because operations such as <, ++, --, and comparisons with 0 are called.
  • Note that advance() does not check whether it crosses the end() of a sequence (it can’t check because iterators in general do not know the containers on which they operate). Thus, calling this function might result in undefined behavior because calling operator ++ for the end of a sequence is not defined.

std::next(and std::prev new in C++11)

#include <iterator>
ForwardIterator next (ForwardIterator pos)
ForwardIterator next (ForwardIterator pos, Dist n)
  • Yields the position the forward iterator pos would have if moved forward 1 or n positions.
  • For bidirectional and random-access iterators, n may be negative to yield previous ositions.
  • Dist is type std::iterator_traits::difference_type.
  • Calls advance(pos,n) for an internal temporary object.
  • Note that next() does not check whether it crosses the end() of a sequence. Thus, it is up to the caller to ensure that the result is valid.

cite from The C++ Standard Library Second Edition

Saviour answered 22/2, 2013 at 5:3 Comment(0)
O
4

They're pretty much the same, except that std::next returns a copy and std::advance modifies its argument. Note that the standard requires std::next to behave like std::advance:

24.4.4 Iterator operations [iterator.operations]

template <class InputIterator, class Distance>
void advance(InputIterator& i [remark: reference], Distance n);

2. Requires: n shall be negative only for bidirectional and random access iterators
3. Effects: Increments (or decrements for negative n) iterator reference i by n.
[...]

template <class ForwardIterator>
ForwardIterator next(ForwardIterator x, [remark: copy]
     typename std::iterator_traits<ForwardIterator>::difference_type n = 1);

6. Effects: Equivalent to advance(x, n); return x;

Note that both actually support negative values if the iterator is an input iterator. Also note that std::next requires the iterator to meet the conditions of an ForwardIterator, while std::advance only needs an Input Iterator (if you don't use negative distances).

Oira answered 22/2, 2013 at 5:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.