23

I found myself writing the following a lot:

int location =2; vector<int> vec; vector<int>::iterator it=vec.begin(); /..../ std::advance(it, location); 

instead of

 it= it + 5; 

what is the Preferred/Recommended way ?

8 Answers 8

24

Adding will only work with random access iterators. std::advance will work with all sorts of iterators. As long as you're only dealing with iterators into vectors, it makes no real difference, but std::advance keeps your code more generic (e.g. you could substitute a list for the vector, and that part would still work).

For those who care, the standard describes advance and distance as follows (§24.3.4/1):

Since only random access iterators provide + and - operators, the library provides two function templates advance and distance. These function templates use + and - for random access iterators (and are, therefore, constant time for them); for input, forward and bidirectional iterators they use ++ to provide linear time implementations.

Also note that starting with C++11, the standard added a parameter to std::next, so you can advance by a specified amount using it (and std::prev similarly). The difference from std::advance is that it returns the modified iterator (which std::advance doesn't), which can be convenient in some cases.

Sign up to request clarification or add additional context in comments.

1 Comment

On the other hand, using less generic code will stop you from unintentionally pessimizing code: after all it might not be a good idea to do lots of "random access" with a list container.
15

That depends on what you need:

If you need genericity, use std::advance(it,2). If someone comes along and changes your std::vector into a std::list, the code will still compile, even though advancing now takes linear time instead of constant time.

If you need performance, use it+=2. If someone comes along and changes your std::vector into a std::list, the code will fail to compile, pointing (maybe with a helpful comment) at a serious performance issue.

2 Comments

For the performance case, if you care that the iterator has random access, maybe it would be better to communicate that with a require clause (concepts) for template code, or a static_assert for non-template code? I haven't tried this before but I think it would work, and be more clear in conveying intent. see std::random_access_iterator
@DavidFong That might well be, but the answer is >12 years old. Concepts were nothing more than a hotly debated concept back then. (Pun not intended, but noted.)
0

It depends on the iterator. it=it+5 is faster if it's supported (it's only supported on random access iterators). If you want to advance a less-capable iterator (e.g. a forward iterator, or a bidirectional iterator), then you can use std::advance, but it's slower because it actually walks across all of the intermediate elements.

7 Comments

You're wrong the standard dictates that std::advance is linear for random access sequences: "Complexity: Constant time if InputIterator is a model of random access iterator, otherwise linear time."
std::advance is constant time for random access iterators (§24.3.4/1).
I don't think that's true for random access iterators - std::advance should be as efficient as the + operator in that case.
@Kylotan: std::advance is required to use '+' when working with a random access iterator, so it's constant complexity. It's not guaranteed to be "as efficient" though -- especially if you turn off optimization, advance might use a function call in cases where + would produce inline code (e.g. if vector::iterator is a simple pointer).
@Jerry - I think you posted that just before I did - my comment was in response to kbloom, but on re-reading the answer I think the wording was just not all that great, since it implies that std::advance is inherently a slower operation.
|
0

std::advance works on non-random iterators too while the += version on works on random access sequences (vectors and the like).

Comments

0

std::adnvance is generic - it is useful if you don't always know type of underlying container - it works in all cases.

Yet it is efficient: std::advance will do an optimisation if it passed an RandomAccessIterator (like one from std::vector) and will increase iterator in loop for ForwardAccessIterator (as like one in std::list).

Comments

0

Use std::advance. It is just as efficient (it uses iterator traits to just do iterator addition for random access iterators), and is more general in that it works on other kinds of iterators as well.

Comments

0

If you're never going to change the container (and you probably aren't), use + because it's easy to see and understand and leaves the code less cluttered.

If you think you want to change the container, OR if you are working inside a template that might be instantiated on various container types, use advance because it works with anything.

As a general rule, I don't worry about changing container types because I've found that when I do have to change a container type, I end up revisiting everywhere that container is used anyway, just to be sure I'm not doing anything that's suddenly stupid (like randomly plucking elements out of the middle of a list).

Comments

0

I use += and + everywhere because it doesn't clutter the code and any so special iterator could also provide += and + operator overloads so the argument about generic programming doesn't really make sense from my point of view.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.