Thursday, 27 April 2017

c++ - Subarray assignment: initialization with "{...}" expected for aggregate object error



What's a good explanation for the error on Line 1?



/* Line 0 */    int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = foo[0];

/* Line 2 */ int foo_alias_also_errors[10] = foo[0];
/* Line 3 */ int * foo_alias_works = foo[0];


The error on Line 2 doesn't really bother me, because I don't need to be able to repeat myself and re-declare the size of the array. However, the error on Line 1 (initialization with "{...}" expected for aggregate object) kind of confuses me. I get that the int foo_alias_compile_error[] is probably the "aggregate object". I just don't get why the language is setup for that not to work. I understand why Line 3 works, but it kind of feels unrepresentative -- it's an array, so I'd rather self-document it as an array.


Answer



One might hope to think of Line 1 as creating a reference for the 0th entry of foo. However, that's not how C++ works. Rather, the assignment operator (=) is invoking a copy operation. So, C++ is interpreting Line 1 as a directive to copy the elements of foo[0] into a new array inappropriately named foo_alias_compile_error.



This isn't what was meant -- one wanted a reference, not a copy. So, it's good that C++ happens to have caused an error for an unrelated reason and saved one from oneself.




A viable solution is suggested by @FrançoisAndrieux. Here's a fuller example showing that a reference (not a copy) can be made with int (&foo_reference)[10] = foo[0];.



int foo[10][10];
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
foo[i][j] = i + j * 10;
}
}
int (&foo_reference)[10] = foo[0];


for (int j = 0; j < 10; ++j) {
foo_reference[j] = 100 + j;
}

for (int i = 0; i < 10; ++i) {
printf("foo [0][%i] is %i\n", i, foo[0][i]);
printf("foo_refer[%i] is %i\n", i, foo_reference[i]);
}



Output Snippet



foo   [0][0] is 100
foo_alias[0] is 100
foo [0][1] is 101
foo_alias[1] is 101
foo [0][2] is 102
foo_alias[2] is 102
foo [0][3] is 103
foo_alias[3] is 103



Side-note



It's worth mentioning that functions that take arrays as arguments implicitly convert their array arguments into pointers (as is shown in Line 3). So, that's one reason why one might incorrectly think something like Line 1 should work.



In other words, the following code



void barz(int arg[]) {
arg[2] = 99999;

}

int another_array[] = {0, 1, 2, 3, 4};
barz(another_array);
printf("another_array[2] is %i\n", another_array[2]);


"Correctly" prints 99999, not 2.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...