What is the correct way of using C++11's range-based for?
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)
range-based for in c++11
No, unluckily. See what the standard says:
The range-based for statement
for ( for-range-declaration : expression ) statement
is equivalent to{
auto && __range = ( expression );
for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
where __range, __begin, and __end are variables defined for exposition only
In other words, it already iterates from begin
to end
and already dereferences the iterator, which you never get to see.
C++11 syntax 'type var : var' is called 'range-based for'
for (char16_t c : str16)
The syntax above defines a range-based for loop (introduced in C++11). It essentially says:
Loop over each character in
str16
, copy the character into a variable calledc
and allow me to use it.
For example:
for (char16_t c : str16)
{
std::cout << c << std::endl;
}
Your second example is a K&R-style C function definition, and is obsolete. See here for more information: Function declaration: K&R vs ANSI
Can range-based C++11 for do/check extra operations/conditions?
Unfortunately, you can't put the increment into the range based for loop. However, in your specific case - as std::vector
stores its elements contigously in memory - you can simulate option 2 by falling back to pointers (thanks to @M.M and @Jarod42 for corrections and improvements):
for ( const int& val : v ) {
std::cout << "v at index " << &val-v.data() << " is " << val;
}
more generic:
for ( const auto& val : v ) {
std::cout << "v at index " << std::addressof(val)-v.data() << " is " << val;
}
The other thing you can do is to write a index_range
class, that represents a collections of indexes over which you can iterate in your range based for loop:
struct index_range_it {
size_t idx;
size_t operator*(){
return idx;
}
index_range_it& operator++() {
idx++;
return (*this);
}
};
bool operator!=(index_range_it l,index_range_it r) {
return l.idx != r.idx;
}
struct index_range {
size_t size;
index_range_it end(){return index_range_it{size};}
index_range_it begin(){return index_range_it{0};}
};
int main()
{
for (auto i: index_range{v.size()}){
std::cout << "v at index " << i << " is " << v[i];
}
}
A full fledged implementation of this idea can be found e.g. here
Such a range can then also be composed to something, where the iterator returns a proxy object containing the index as well as a reference to the current object and with c++17's structured binding that would be even more convenient to use.
Is it safe to use a C++11 range-based for-loop with an rvalue range-init?
Yes, it's perfectly safe.
From [class.temporary]/4-5:
There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called [...]
The second context is when a reference is bound to a temporary. The temporary to which the reference is
bound or the temporary that is the complete object of a subobject to which the reference is bound persists
for the lifetime of the reference except:
- A temporary bound to a reference member in a constructor’s ctor-initializer [...]
- A temporary bound to a reference parameter in a function call [...]
- The lifetime of a temporary bound to the returned value in a function return statement [...]
- A temporary bound to a reference in a new-initializer [...]
None of those exceptions apply. The temporary thus persists for the lifetime of the reference, __range
, which is the entire loop.
C++11 Using Range-based for loop (for each) for dynamic array
Just use a container-like wrapper:
template <typename T>
struct Wrapper
{
T* ptr;
std::size_t length;
};
template <typename T>
Wrapper<T> make_wrapper(T* ptr, std::size_t len) {return {ptr, len};}
template <typename T>
T* begin(Wrapper<T> w) {return w.ptr;}
template <typename T>
T* end(Wrapper<T> w) {return begin(w) + w.length;}
Usage:
for (auto i : make_wrapper(a, sizeof a / sizeof *a))
std::cout << i << ", ";**
Demo.
With C++1Z we will hopefully be able to use std::array_view
instead.
C++11 range-based for loops without loop variable
There may be a way to do it but I very much doubt it would be more elegant. What you have in that first loop is already the correct way to do it, limiting the scope/lifetime of the loop variable.
I would simply ignore the unused variable warning (it's only an indication from the compiler that something may be wrong, after all) or use the compiler facilities (if available) to simply turn off the warning at that point.
This may be possible with some sort of #pragma
depending on your environment, or some implementations allow you to do things like:
for (int x = 0; x < 10; ++x) {
(void)x;
// Other code goes here, that does not reference "x".
}
I've seen that void
trick used for unused parameters in function bodies.
How does the C++11 range-based for loop know the array size?
This is simply something that the language requires to work, and the compiler must implement. Obviously the complete type of my_array
is int[5]
(i.e. the size is part of the type), so this information is readily available.
Contrary to popular belief, there is no use of the free std::begin()
/std::end()
functions in play, although those would naively seem to be able to do the trick (but there's a catch involving ADL that would break this approach).
Is there a range class in C++11 for use with range based for loops?
The C++ standard library does not have one, but Boost.Range has boost::counting_range, which certainly qualifies. You could also use boost::irange, which is a bit more focused in scope.
C++20's range library will allow you to do this via view::iota(start, end)
.
Can C++11 and C++17 Range-Based For Loop iterate to a specific position instead of full range of the map?
You either need an external counter to make early exit, eg:
int n = 0;
for(auto [k, v] : map)
{
if(++n > 10) break;
std::cout << k << ": " << v << std::endl;
}
Or, if you are not afraid of copying the map, you can do:
std::map<...> copy { map.begin(), std::next(map.begin(), 10) };
for(auto [k, v] : copy) std::cout << k << ": " << v << std::endl;
Finally, if you can use C++20, then you can simply do this:
#include <ranges>
for(auto [k, v] : map | std::views::take(10))
{
std::cout << k << ": " << v << std::endl;
}
Related Topics
How to Use Queryperformancecounter
C++ Templates That Accept Only Certain Types
How to Implement an Stl-Style Iterator and Avoid Common Pitfalls
What's the Difference Between Assignment Operator and Copy Constructor
Is "Argv[0] = Name-Of-Executable" an Accepted Standard or Just a Common Convention
Linux API to List Running Processes
Debugging Core Files Generated on a Customer'S Box
Measuring Execution Time of a Function in C++
Legality of Cow Std::String Implementation in C++11
Which, If Any, C++ Compilers Do Tail-Recursion Optimization
What's the Best Free C++ Profiler For Windows
Range Based Loop: Get Item by Value or Reference to Const
Namespace + Functions Versus Static Methods on a Class