6

Given a vector, vc, one can iterate through the vector with a range for:

for (auto c : vc)
    std::cout << c;

Or with an iterator:

for (auto it = vc.cbegin(); it != vc.cend(); ++it)
    std::cout << *it;

Is there a functional reason to use one method over the other, or is this merely a matter of style?

1
  • 5
    note that with your use of auto in the range-based for-loop you're getting a copy of your vector elements, which, if your object is expensive to copy, may yield unwanted performance issues. With the use of iterators you get back a const reference, so the copies don't happen here. A way to get back a const reference in the range-based for is for (const auto& c : vc) ... Commented Feb 15, 2016 at 19:24

4 Answers 4

4

From the performance point of view there isn't really a difference. As Bjarne Stroustrup writes in his book the C++ Programming language 4th edition:

The simplest loop is a range- for -statement; it simply gives the programmer access to each element of a range.

As a fan of the KISS principle I tend to prefer simpler constructs over more complex ones. However, it really boils down to what you want to achieve. From the same book Bjarne reveals why a range-for loop is designed to be simple:

Note that a range- for loop is a deliberately simple construct. For example, using it you can’t touch two elements at the same time and can’t effectively traverse two ranges simultaneously. For that we need a general for-statement.

Consequently, there are contexts that you can't use a range-for loop and you have to reside to the classical for-statement.

Bottom line use range-for loop when ever possible because is simpler and more readable.

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

Comments

4

It is more or less a matter of style, but consider it this way; range-for loops are more concise than explicit iterator usage. The less code you write, the less places where things can go wrong.

2 Comments

Also, it's a whole lot more readable, as it hides the implementation details of the loop.
Range for may also be clearer to compilers, improving optimizability.
3

There are two substantive differences between your two examples. First, auto c creates a copy of each element, so use auto const& c if you don't want to create unnecessary copies. Second, range for is implemented in terms of non-const iterators, but your for loop uses const iterators. That doesn't matter if vc is a standard container, but some containers (e.g. those in Qt) implement copy-on-write semantics using an internal shared pointer, in which case the use of non-const iterators will unnecessarily copy the entire container. You can avoid this and still use the nice range for syntax by using C++17 std::as_const:

for (auto const& c : std::as_const(vc))
    std::cout << c;

You can easily implement your own version of as_const if your environment doesn't provide it.

Comments

2

For your specific example, they are equivalent. And since they are equivalent, you naturally want to prefer the shortest version which happens to also be the least error-prone -- for free.

The range-for loop was also proposed to be shortened furthermore to:

for ( var : range )

where var would have type auto&& (aka forwading/universal reference), which is the best way to take a reference to an object. Just auto var will make a copy of each element, which might not be cheap. Unfortunately, it did not pass.

You typically don't work with iterators directly so range-for you should be your first choice. Explicit iterators may also point to out-of-range elements since you can freely move in the range, leading to undefined behavior.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.