I'm trying to understand the nature of type-decay. For example, we all know arrays decay into pointers in a certain context. My attempt is to understand how int[]
equates to int*
but how two-dimensional arrays don't correspond to the expected pointer type. Here is a test case:
std::is_same<int*, std::decay<int[]>::type>::value; // true
This returns true as expected, but this doesn't:
std::is_same<int**, std::decay<int[][1]>::type>::value; // false
Why is this not true? I finally found a way to make it return true, and that was by making the first dimension a pointer:
std::is_same<int**, std::decay<int*[]>::type>::value; // true
And the assertion holds true for any type with pointers but with the last being the array. For example (int***[] == int****; // true
).
Can I have an explanation as to why this is happening? Why doesn't the array types correspond to the pointer types as would be expected?
From Code 1, whenever arrays are passed as the arguments to functions, they are always passed by using the 'Pass by reference' mechanism. Because of this, they will decay into pointers in the function parameters.
The loss of type and dimensions of an array is known as array decay. It occurs when we pass the array into a function by pointer or value. First address is sent to the array which is a pointer. That is why, the size of array is not the original one.
Why does
int*[]
decay intoint**
but notint[][]
?
Because it would be impossible to do pointer arithmetic with it.
For example, int p[5][4]
means an array of (length-4 array of int
). There are no pointers involved, it's simply a contiguous block of memory of size 5*4*sizeof(int)
. When you ask for a particular element, e.g. int a = p[i][j]
, the compiler is really doing this:
char *tmp = (char *)p // Work in units of bytes (char) + i * sizeof(int[4]) // Offset for outer dimension (int[4] is a type) + j * sizeof(int); // Offset for inner dimension int a = *(int *)tmp; // Back to the contained type, and dereference
Obviously, it can only do this because it knows the size of the "inner" dimension(s). Casting to an int (*)[4]
retains this information; it's a pointer to (length-4 array of int
). However, an int **
doesn't; it's merely a pointer to (pointer to int
).
For another take on this, see the following sections of the C FAQ:
(This is all for C, but this behaviour is essentially unchanged in C++.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With