Is range-based for-loop to iterate over an char[] is undefined-behavior?

188 Views Asked by At

(assuming that I can not use STL container)

#include <iostream>

int main()
{
    wchar_t my_array[] = { L'h', L'e', L'l', L'l', L'o' };

    for (const auto& wch : my_array) {
        std::wcout << wch;
    }
}

The range-based for loop in C++ uses the begin() and end() functions to determine the range of elements to iterate over. In the case of an array, as above, std::begin(my_array) returns a pointer to the first element of the array, and std::end(my_array) returns a pointer to one past the last element of the array.

It works, but is it UB?

3

There are 3 best solutions below

0
463035818_is_not_an_ai On BEST ANSWER

No. It is not undefined.

A pointer can point one past the last element of an array.

Actually std::vector iterators can be implemented as raw pointers. Also a pointer to an object can be regarded as pointer to a single element array. Incrementing such pointer once is legal. You just may not dereference it. The end pointer / iterator is not dereferenced in the ranged based for loop. Dereferencing the end iterator would be UB as well as dereferencing the pointer.

int a[] = {1,2,3};
int* a_end = a + 3;  // OK
// *a_end ... NOT OK

int x = 42;
int p = &x;
int* p_one_past = p+1;      // not that useful, but OK
// *p_one_past ... NOT OK

Also when using c-style arrays with algorithms that expect first and last iterators it is common to pass a one-past-last-element pointer:

int a[] = {3,2,1};
std::sort( std::begin(a) , std::end(a) );

Here std::end(a) is the same as a + std::size(a) is the same as a + 3.

0
Ivaylo Strandjev On

The situation you describe does not lead to undefined behaviour. Iterating over a char array is not much different than iterating any other array. Note that in c++ end is supposed to point to one element past the last element in the collection. This is not an exception in this case, but the norm and is also what for each loop in c++ expects.

0
wohlstad On

No this is not UB.

As a matter of fact it is quite similar to using a range-based for loop with an stl container like std::vector. The std::vector::end() iterator in practice also points to one element past the last element of the std::vector.

If you would dereference it, it would be UB, but this is not required for executing a ranged-based for loop.