Friday, December 24, 2010

Returning Arrays by Reference in C++

Last article we talked about returning arrays, but we only did it by value (so that a copy of the data is returned). This time we'll look at returning arrays using references.

This feature is something that I rarely see used in practice, I think partially because the syntax is so bizarre and confusing to those that have never seen it. I first saw it in some code by shuffle2 and thought it was crazy; but now I understand why the syntax is the way it is.

Here's how to do it:

int testArr[5] = { 1000, 1, 2, 3, 4 };

int (&retArr())[5] {
return testArr;
}

int main() {
int (&arr)[5] = retArr();
cout << arr[0] << endl; // prints 1000
return 0;
}


The 'retArr()' is the function which is returning a reference to an int array with 5 elements. If you wanted any parameters for the function 'retArr()' you can place them in the '()' like you normally would.

The seemingly awkward syntax becomes less awkward when you think of the syntax for declaring references to an array.
'int (&arr)[5] = ...' is how you would declare a normal reference to an array, so studying that syntax and then looking at the function prototype 'int (&retArr())[5]' should help you understand it.

Also why is returning a reference to an array useful?
Well its useful for various reasons, but I'll give an interesting example.

Assume that you have a memory buffer that was dynamically allocated (for w/e reason, maybe a custom allocation routine to guarantee alignment), then you want that buffer to be thought of as a fixed-size array; well you can do that by returning a reference to an array.

Like so:

struct myStruct {
int* myPtr;
myStruct() {
myPtr = new int[5];
myPtr[0] = 1000;
myPtr[1] = 1;
myPtr[2] = 2;
myPtr[3] = 3;
myPtr[4] = 4;
}
~myStruct() {
delete[] myPtr;
}
int (&getArray())[5] {
return (int(&)[5])*myPtr; // cast to a reference
}
};

int main() {
myStruct testStruct;
cout << testStruct.getArray()[0] << endl; // prints 1000
cout << sizeof(testStruct.getArray()) << endl; // prints 20
return 0;
}


The benefit of returning an array by reference instead of just an int pointer in the above code is that the former explicitly tells the programmer reading the function signature that the buffer being returned holds 5 ints, returning an int pointer instead will not tell us how much elements are in the array.
Also sizeof(testStruct.getArray()) returns 5*sizeof(int), whereas if we were returning an int pointer, it would just return sizeof(int*), which most-likely isn't what we wanted.

1 comment: