Why is an array's dimension part of its type?

What's going on behind the scenes?

A non dynamically-allocated is, by definition, a fixed-size container of homogeneous elements. An array of N elements of type T is laid out in memory as a contiguous sequence of N objects of type T.


Why is it necessary to for array's to have a type that includes it's size?

I do not believe it is "necessary" for an array's type to include it's size - as a matter of fact, you can use a pointer to refer to a contiguous sequence of T objects. Such pointer would lose size information about the array.

It is, however, a useful thing to have. It improves type safety, and encodes useful information at compile-time that can be used in multiple ways. As an example, you can use references-to-arrays to overload on arrays of different sizes

void foo(int(&array)[4]) { /* ... */ }
void foo(int(&array)[8]) { /* ... */ }

or to figure out the size of an array as a constant expression

template <typename T, std::size_t N>
constexpr auto sizeOf(const T(&array)[N]) { return N; }

How will this affect comparing arrays?

It doesn't, really.

You cannot compare C-style arrays in the same way you would compare two numbers (e.g. int objects). You would have to write some sort of lexicographical comparison, and decide what it means for collections of different sizes. std::vector<T> provides that, and the same logic can be applied to arrays.


Bonus: C++11 and above provides std::array, which is a wrapper around a C-style array with a container-like interface. It should be preferred to C-style arrays as it is more consistent with other containers (e.g. std::vector<T>), and also supports lexicographical comparisons out of the box.


The amount of space that is allocated to an object when you create it depends entirely on its type. The allocation I'm talking about isn't allocations from new or malloc, but the space that is allocated so that you can run your constructor and initialize your object.

If you have a struct defined as (for example)

struct A { char a, b; }; //sizeof(A) == 2, ie an A needs 2 bytes of space

Then when you construct the object:

A a{'a', 'b'};

You can think of the process of constructing the object as a process:

  • Allocate 2 bytes of space (on the stack, but where doesn't matter for this example)
  • Run object's constructor (in this case copy 'a' and 'b' to the object)

It's important to note that the 2 bytes of space needed is entirely determined by the type of the object, the arguments to the function don't matter. So, for an array the process is the same, except now the amount of space needed depends on the number of elements in the array.

char a[] = {'a'}; //need space for 1 element
char b[] = {'a', 'b', 'c', 'd', 'e'}; //need space for 5 elements

So the types of a and b must reflect the fact that a needs enough space for 1 char and b needs enough space for 5 chars. That does mean that the size of these arrays cannot suddenly change, once a 5-element array is created it is always a 5-element array. In order to have "array"-like objects where the size can vary, you need dynamic memory allocation, which your book should be cover at some point.

Tags:

C++

Arrays

C++11