What is the correct way of using C++11's range-based for?

c++, c++11, foreach

Solution

TL;DR: Consider the following guidelines:

For observing the elements, use the following syntax:

for (const auto& elem : container)    // capture by const reference

If the objects are cheap to copy (like `int`s, `double`s, etc.), it's possible to use a slightly simplified form:

  for (auto elem : container)    // capture by value

For modifying the elements in place, use:

for (auto& elem : container)    // capture by (non-const) reference

If the container uses "proxy iterators" (like `std::vector<bool>`), use:

  for (auto&& elem : container)    // capture by &&

Of course, if there is a need to make a local copy of the element inside the loop body, capturing by value (`for (auto elem : container)`) is a good choice.

Detailed Discussion

Let's start differentiating between observing the elements in the container vs. modifying them in place.

Observing the elements

Let's consider a simple example:

vector<int> v = {1, 3, 5, 7, 9};

for (auto x : v)
    cout << x << ' ';

The above code prints the elements (`int`s) in the `vector`:

1 3 5 7 9

Now consider another case, in which the vector elements are not just simple integers, but instances of a more complex class, with custom copy constructor, etc.

// A sample test class, with custom copy semantics.
class X
{
public:
    X() 
        : m_data(0) 
    {}
    
    X(int data)
        : m_data(data)
    {}
    
    ~X() 
    {}
    
    X(const X& other) 
        : m_data(other.m_data)
    { cout << "X copy ctor.\n"; }
    
    X& operator=(const X& other)
    {
        m_data = other.m_data;       
        cout << "X copy assign.\n";
        return *this;
    }
       
    int Get() const
    {
        return m_data;
    }
    
private:
    int m_data;
};

ostream& operator<<(ostream& os, const X& x)
{
    os << x.Get();
    return os;
}

If we use the above `for (auto x : v) {...}` syntax with this new class:

vector<X> v = {1, 3, 5, 7, 9};

cout << "\nElements:\n";
for (auto x : v)
{
    cout << x << ' ';
}

the output is something like:

[... copy constructor calls for vector<X> initialization ...]

Elements:
X copy ctor.
1 X copy ctor.
3 X copy ctor.
5 X copy ctor.
7 X copy ctor.
9

As it can be read from the output, copy constructor calls are made during range-based for loop iterations. This is because we are capturing the elements from the container by value (the `auto x` part in `for (auto x : v)`).

This is inefficient code, e.g., if these elements are instances of `std::string`, heap memory allocations can be done, with expensive trips to the memory manager, etc. This is useless if we just want to observe the elements in a container.

So, a better syntax is available: capture by `const` reference, i.e. `const auto&`:

vector<X> v = {1, 3, 5, 7, 9};

cout << "\nElements:\n";
for (const auto& x : v)
{ 
    cout << x << ' ';
}

Now the output is:

 [... copy constructor calls for vector<X> initialization ...]

Elements:
1 3 5 7 9

Without any spurious (and potentially expensive) copy constructor call.

So, when observing elements in a container (i.e., for read-only access), the following syntax is fine for simple cheap-to-copy types, like `int`, `double`, etc.:

for (auto elem : container) 

Else, capturing by `const` reference is better in the general case, to avoid useless (and potentially expensive) copy constructor calls:

for (const auto& elem : container) 

Modifying the elements in the container

If we want to modify the elements in a container using range-based `for`, the above `for (auto elem : container)` and `for (const auto& elem : container)` syntaxes are wrong.

In fact, in the former case, `elem` stores a copy of the original element, so modifications done to it are just lost and not stored persistently in the container, e.g.:

vector<int> v = {1, 3, 5, 7, 9};
for (auto x : v)  // <-- capture by value (copy)
    x *= 10;      // <-- a local temporary copy ("x") is modified,
                  //     *not* the original vector element.

for (auto x : v)
    cout << x << ' ';

The output is just the initial sequence:

1 3 5 7 9

Instead, an attempt of using `for (const auto& x : v)` just fails to compile.

g++ outputs an error message something like this:

TestRangeFor.cpp:138:11: error: assignment of read-only reference 'x'
          x *= 10;
            ^

The correct approach in this case is capturing by non-`const` reference:

vector<int> v = {1, 3, 5, 7, 9};
for (auto& x : v)
    x *= 10;

for (auto x : v)
    cout << x << ' ';

The output is (as expected):

10 30 50 70 90

This `for (auto& elem : container)` syntax works also for more complex types, e.g. considering a `vector<string>`:

vector<string> v = {"Bob", "Jeff", "Connie"};

// Modify elements in place: use "auto &"
for (auto& x : v)
    x = "Hi " + x + "!";
    
// Output elements (*observing* --> use "const auto&")
for (const auto& x : v)
    cout << x << ' ';
    

the output is:

Hi Bob! Hi Jeff! Hi Connie!

The special case of proxy iterators

Suppose we have a `vector<bool>`, and we want to invert the logical boolean state of its elements, using the above syntax:

vector<bool> v = {true, false, false, true};
for (auto& x : v)
    x = !x;

The above code fails to compile.

g++ outputs an error message similar to this:

TestRangeFor.cpp:168:20: error: invalid initialization of non-const reference of
 type 'std::_Bit_reference&' from an rvalue of type 'std::_Bit_iterator::referen
ce {aka std::_Bit_reference}'
     for (auto& x : v)
                    ^

The problem is that `std::vector` template is specialized for `bool`, with an implementation that packs the `bool`s to optimize space (each boolean value is stored in one bit, eight "boolean" bits in a byte).

Because of that (since it's not possible to return a reference to a single bit), `vector<bool>` uses a so-called "proxy iterator" pattern. A "proxy iterator" is an iterator that, when dereferenced, does not yield an ordinary `bool &`, but instead returns (by value) a temporary object, which is a proxy class convertible to `bool`. (See also this question and related answers here on StackOverflow.)

To modify in place the elements of `vector<bool>`, a new kind of syntax (using `auto&&`) must be used:

for (auto&& x : v)
    x = !x;

The following code works fine:

vector<bool> v = {true, false, false, true};

// Invert boolean status
for (auto&& x : v)  // <-- note use of "auto&&" for proxy iterators
    x = !x;

// Print new element values
cout << boolalpha;        
for (const auto& x : v)
    cout << x << ' ';
    

and outputs:

false true true false

Note that the `for (auto&& elem : container)` syntax also works in the other cases of ordinary (non-proxy) iterators (e.g. for a `vector<int>` or a `vector<string>`).

(As a side note, the aforementioned "observing" syntax of `for (const auto& elem : container)` works fine also for the proxy iterator case.)

Summary

The above discussion can be summarized in the following guidelines:

For observing the elements, use the following syntax:

for (const auto& elem : container)    // capture by const reference

If the objects are cheap to copy (like `int`s, `double`s, etc.), it's possible to use a slightly simplified form:

  for (auto elem : container)    // capture by value

For modifying the elements in place, use:

for (auto& elem : container)    // capture by (non-const) reference

If the container uses "proxy iterators" (like `std::vector<bool>`), use:

  for (auto&& elem : container)    // capture by &&

Of course, if there is a need to make a local copy of the element inside the loop body, capturing by value (`for (auto elem : container)`) is a good choice.

Additional notes on generic code

In generic code, since we can't make assumptions about generic type `T` being cheap to copy, in observing mode it's safe to always use `for (const auto& elem : container)`. (This won't trigger potentially expensive useless copies, will work just fine also for cheap-to-copy types like `int`, and also for containers using proxy-iterators, like `std::vector<bool>`.)

Moreover, in modifying mode, if we want generic code to work also in case of proxy-iterators, the best option is `for (auto&& elem : container)`. (This will work just fine also for containers using ordinary non-proxy-iterators, like `std::vector<int>` or `std::vector<string>`.)

So, in generic code, the following guidelines can be provided:

For observing the elements, use:

for (const auto& elem : container)

For modifying the elements in place, use:

for (auto&& elem : container)

Problem

What is the correct way of using C++11's range-based `for`? What syntax should be used? `for (auto elem : container)`, or `for (auto& elem : container)` or `for (const auto& elem : container)`? Or some other?

Original source

Related problems