You can't perform a range based loop directly over a dynamically allocated array because all you have is a pointer to the first element. There is no information concerning its size that the compiler can use to perform the loop.
Range-based for loop in C++ Also Sequence of elements in braces can be used. loop-statement − body of for loop that contains one or more statements that are to be executed repeatedly till the end of range-expression.
A range-based for loop terminates when one of these in statement is executed: a break , return , or goto to a labeled statement outside the range-based for loop. A continue statement in a range-based for loop terminates only the current iteration.
A dynamic array is an array with a big improvement: automatic resizing. One limitation of arrays is that they're fixed size, meaning you need to specify the number of elements your array will hold ahead of time. A dynamic array expands as you add more elements. So you don't need to determine the size ahead of time.
To make use of the range-based for-loop you have to provide either begin()
and end()
member functions or overload the non-member begin()
and end()
functions.
In the latter case, you can wrap your range in a std::pair
and overload begin()
and end()
for those:
namespace std {
template <typename T> T* begin(std::pair<T*, T*> const& p)
{ return p.first; }
template <typename T> T* end(std::pair<T*, T*> const& p)
{ return p.second; }
}
Now you can use the for-loop like this:
for (auto&& i : std::make_pair(array, array + size))
cout << i << endl;
Note, that the non-member begin()
and end()
functions have to be overloaded in the std
namespace here, because pair
also resides in namespace std
. If you don't feel like tampering with the standard namespace, you can simply create your own tiny pair class and overload begin()
and end()
in your namespace.
Or, create a thin wrapper around your dynamically allocated array and provide begin()
and end()
member functions:
template <typename T>
struct wrapped_array {
wrapped_array(T* first, T* last) : begin_ {first}, end_ {last} {}
wrapped_array(T* first, std::ptrdiff_t size)
: wrapped_array {first, first + size} {}
T* begin() const noexcept { return begin_; }
T* end() const noexcept { return end_; }
T* begin_;
T* end_;
};
template <typename T>
wrapped_array<T> wrap_array(T* first, std::ptrdiff_t size) noexcept
{ return {first, size}; }
And your call site looks like this:
for (auto&& i : wrap_array(array, size))
std::cout << i << std::endl;
Example
You can't use range-for-loop with dynamically allocated arrays, since compiler can't deduce begin and end of this array. You should always use containers instead of it, for example std::vector
.
std::vector<int> v(size);
for(const auto& elem: v)
// do something
You can't perform a range based loop directly over a dynamically allocated array because all you have is a pointer to the first element. There is no information concerning its size that the compiler can use to perform the loop. The idiomatic C++ solution would be to replace the dynamically allocated array by an std::vector
:
std::vector<int> arr(size);
for(const auto& i : arr)
std::cout<< i << std::endl;
Alternatively, you could use a range type that provides a begin and end iterator based on a pointer and an offset. Have a look at some of the types in the boost.range library, or at the GSL span proposal (example implementation here, reference for C++20 proposed type here).
Note that a range based for loop does work for std::array
objects of fixes size plain arrays:
std::array<int,10> arr;
for(const auto& i : arr)
std::cout<< i << std::endl;
int arr[10] = .... ;
for(const auto& i : arr)
std::cout<< i << std::endl;
but in both cases the size needs to be a compile-time constant.
C++20 will (presumably) add std::span
, which allows looping like this:
#include <iostream>
#include <span>
int main () {
auto p = new int[5];
for (auto &v : std::span(p, 5)) {
v = 1;
}
for (auto v : std::span(p, 5)) {
std::cout << v << '\n';
}
delete[] p;
}
This is supported by current compilers, e.g. gcc 10.1 and clang 7.0.0 and later. (Live)
Of course, if you have the choice, it is preferable to use std::vector
over C-style arrays from the get-go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With