Prefer Using References With Range Based For Loops


Now and again I see people forgetting the & in range based for loops, like this:

    for (auto a : a_vec)
    {
    }

What some people seem to forget, or don’t know, is that this creates a copy of the element for each iteration. Unless you actually need a copy, there is no need to perform it. And if the objects you are copying are any larger than a built-in type (integer, pointer etc.), there is a potential performance penalty. So by default, do this instead:

    for (const auto& a : a_vec)
    {
    }

Notice the &? Now you get a reference instead of a copy, which is typically cheaper. Here is the full program:

#include <iostream>
#include <vector>

using namespace std;

class A
{
public:
    A() = default;
    A(const A& rhs) { cout << "Copy" << endl; }
};

int main()
{
    vector<A> a_vec(2);

    cout << "Range based for without &" << endl;
    for (auto a : a_vec)
    {
    }

    cout << "Range based for with &" << endl;
    for (const auto& a : a_vec)
    {
    }
}

And its output:

Range based for without &
Copy
Copy
Range based for with &

Afterthought: Why?

Why are people doing this? It might be that people are used to iterating with iterators, where you get a cheap copy of the iterator, not the actual object:

    for (auto a = a_vec.cbegin(); a != a_vec.cend(); ++a)
    {
    }

Here, a is an iterator, not the actual object, so copying it is inexpensive.

As usual, the code for this blog post is available on GitHub.

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter.

C++0x highlights #0: Range Based For Loop


Herb Sutter has some good news, C++0x looks like it could end up as C++11! This is going to be a great update to the C++ language. Lots of advanced features, like closures, a new memory model, portable threading support etc., are coming, but I think the one that I miss most often is the really simple Range Based For Loop (especially combined with Type Inference).

The following for loop:

map<SomeClass, vector> someclass_strings_map;
for (map<SomeClass, vector>::const_iterator it = someclass_strings_map.begin();
    it != someclass_strings_map.end(); ++it) {
    do_something_with(it->second);
}

is one of the reasons the Python, Ruby (and Java since 1.5) people laugh at us. But next year, we will be able to do:

for (auto x : foo_strings_map) {
        do_something_with(x.second);
}

PS: while I was compiling this example, I remembered another tiny improvement, you can now do map<Foo, vector<string>>. Notice the missing space? C++ no longer confuses nested templates with the shift/stream operator. Currently, you need an extra space: map<Foo, vector<string> >

PPS: If do_something_with() is a simple function this could be done with a for_each and a lambda/closure, but that is another story.

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter.