What is useful about a reference-to-array parameter?

Dan picture Dan · Feb 3, 2010 · Viewed 11.9k times · Source

I recently found some code like this:

typedef int TenInts[10];
void foo(TenInts &arr);

What can you do in the body of foo() that is useful, that you could not do if the declaration was:

void foo(int *arr);    // or,
void foo(int arr[]);   // or,
void foo(int arr[10]); // ?

I found a question that asks how to pass a reference to an array. I guess I am asking why.

Also, only one answer to "When is pointer to array useful?" discussed function parameters, so I don't think this is a duplicate question.

Answer

AnT picture AnT · Feb 3, 2010

The reference-to-array parameter does not allow array type to decay to pointer type. i.e. the exact array type remains preserved inside the function. (For example, you can use the sizeof arr / sizeof *arr trick on the parameter and get the element count). The compiler will also perform type checking in order to make sure the array argument type is exactly the same as the array parameter type, i.e. if the parameter is declared as a array of 10 ints, the argument is required to be an array of exactly 10 ints and nothing else.

In fact, in situations when the array size is fixed at compile-time, using a reference-to-array (or pointer-to-array) parameter declarations can be preceived as the primary, preferred way to pass an array. The other variant (when the array type is allowed to decay to pointer type) are reserved for situations when it is necessary to pass arrays of run-time size.

For example, the correct way to pass an array of compile-time size to a function is

void foo(int (&arr)[10]); // reference to an array

or

void foo(int (*arr)[10]); // pointer to an array

An arguably incorrect way would be to use a "decayed" approach

void foo(int arr[]); // pointer to an element
// Bad practice!!!

The "decayed" approach should be normally reserved for arrays of run-time size and is normally accompanied by the actual size of the array in a separate parameter

void foo(int arr[], unsigned n); // pointer to an element
// Passing a run-time sized array

In other words, there's really no "why" question when it comes to reference-to-array (or pointer-to-array) passing. You are supposed to use this method naturally, by default, whenever you can, if the array size is fixed at compile-time. The "why" question should really arise when you use the "decayed" method of array passing. The "decayed" method is only supposed to be used as a specialized trick for passing arrays of run-time size.

The above is basically a direct consequence of a more generic principle. When you have a "heavy" object of type T, you normally pass it either by pointer T * or by reference T &. Arrays are no exception from this general principle. They have no reason to be.

Keep in mind though that in practice it is often makes sense to write functions that work with arrays of run-time size, especially when it comes to generic, library-level functions. Such functions are more versatile. That means that often there's a good reason to use the "decayed" approach in real life code, Nevertheless, this does not excuse the author of the code from recognizing the situations when the array size is known at compile time and using the reference-to-array method accordingly.