9

When I do something like this:

int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array) {
    x *= 2;
}

C++11 obviously knows that my array only has 5 elements. Is this information stored somewhere in the my_array object?

If so, is there any good reason why it is not made available to me as a developer (or is it?!?!?)? It seems that a lot of the world's problems would be solved if C++ devs always knew the bounds of the arrays they're dealing with.

3 Answers 3

11

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).

Sign up to request clarification or add additional context in comments.

4 Comments

Ok. So is there any particular reason why a my_array.size does not exist?
@suslik: Sure, because arrays are not class types and thus cannot have member functions. But you can trivially write an array_size free function template that produces the desired value, or use the readily-made std::extent.
How did I live my life not knowing about this for so long... I blame std::vector :).
@suslik: Because std::extent is new C++11 stuff too. Those mechanics (the type of arrays being part of the type) aren't new, so std::extent could always have been written. They just didn't until recently.
6

It is available - you can define begin and end on arrays in standard C++. The size of the array is encoded in the type.

The general method is to use references to arrays.

Here's an example size function:

template<typename T, size_t N>
size_t array_size(T (& const)[N])
{
    return N;
}

1 Comment

This is also known as std::extent. And std::begin and std::end are already defined for arrays in the standard library.
5

No, it's not part of the object. But it's part of the type. That's what the 5 in the array declaration is. However, this won't work:

void f(int arr[5]) {
    for(int& x: arr) {
        // whatever
    }
}

because the name of the array here decays into a pointer to its first element, that is, the argument declaration is equivalent to int *arr which has no size information.

2 Comments

I wouldn't use the term 'decay' in this instance. I think that term is usually specific to the implicit conversion done to an array variable in many expressions. int a[5]; a + 1; // decay Instead I like to refer to what happens here with the term 'adjust' as that's the word the standard uses. void foo(int a[5]); // type 'adjustment': equivalent to void foo(int *a). And I like to use a sarcastic tone when I say the word.
For reference, @balki's solution doesn't work with unsized array references, e.g. (&arr)[5]. But it can usually be made to work for generic-sized arrays by using the array size as a template parameter: see stackoverflow.com/questions/26182907/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.