简体   繁体   中英

Why does not std::advance return the resulting iterator?

Currently, std::advance is designed like this:

template< class InputIt, class Distance >
void advance( InputIt& it, Distance n );

However, I frequently find myself want something like:

template< class InputIt, class Distance >
InputIt advance( InputIt it, Distance n );

So, what is the rationale behind the current design? Is this for some performance consideration? Note that std::next and std::prev do return the resulting iterator.

There is no technical reason preventing it to return a reference to the input value, and any reasonable compiler should be able to optimize the return value out if it's not used. So they could have done it that way if they wanted to.

I think their choice makes sense from an API design point of view though - std::prev and std::next take an iterator and return a different iterator pointing to the previous or next element, respectively, without modifying the input .

std::advance on the other hand modifies the input. If it returned a reference to the input iterator, it might be confused for a function that returns a copy without modifying the input in-place. That could potentially be dangerous.

Note that std::advance works with InputIterator s, which includes iterators where iteration has side effects (things such as iterators that read from streams), but std::prev and std::next only work with ForwardIterator s, which do not have side effects.

So returning a separate value (like std::prev and std::next ) would be a bad idea - you'd end up with two iterators on the same stream, which may affect each other adversely.

The main reason, as indicated in the comments section is that an InputIterator does not guarantee that after incrementing an iterator, any previous iterators will still be valid:

InputIterators only guarantee validity for single pass algorithms: once an InputIterator i has been incremented, all copies of its previous value may be invalidated.

Thus if std::advance returned a copy the caller could end up with two iterators of which one could be invalid. The interface with a reference indicates that this is not how input iterators should be used.

std::prev and std::next on the other hand take a BidirectionalIterator , which among others, satisfies requirements for a ForwardIterator :

Unlike InputIterator and OutputIterator, it can be used in multipass algorithms.

So, you can move an iterator while still holding a copy of its previous position.

Here is a nice table that clearly presents relations between different iterator concepts.


Of course one may argue that the caller should be aware of how InputIterator works and should be allowed to have the convenience of choosing a version that suits their current need. An example of such issue was presented by dyp in the comments section: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2353 .

Pleasing everyone however always leads to an explosion of the number of methods in an interface.

The link suggests that what is now is a state of a to-be-consensus.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM