tags:

views:

232

answers:

7

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 ?

A: 

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.

Ken Bloom
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."
Blindy
std::advance is constant time for random access iterators (§24.3.4/1).
Jerry Coffin
I don't think that's true for random access iterators - std::advance should be as efficient as the + operator in that case.
Kylotan
@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 Coffin
@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.
Kylotan
I didn't realize that it was possible (and certainly not easy) to specialize std::advance() for *all* random-access iterators.
Ken Bloom
A: 

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

Blindy
+6  A: 

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).

Edit: 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.
Jerry Coffin
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.
UncleBens
A: 

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).

Aleksei Potov
+1  A: 

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.

navigator
+1  A: 

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.

sbi
A: 

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).

Michael Kohne