Understanding the order in new[] - c++

I understand that the usage of new[] is: new <type>[<size>].
Now, suppose I'd like to allocate a matrix with the number of columns nCols known at compile time. In terms of the above usage, type is int[nCols]. So, I would think to write:
const int nCols = 5;
int nRows;
cin >> nRows;
int (*matrix)[nCols] = new (int[nCols]) [nRows];
How come the correct way of writing it is actually new int[nRows][nCols]?

How come the correct way of writing it is actually new int[nRows][nCols]?
Simply put, because you’re allowed to put parentheses around expressions (1 + 1 and (1 + 1) are both valid and evaluate to the same), but you are not allowed to put parentheses around arbitrary types (int is a valid type but (int) isn’t).
Parentheses inside a type name always have have a semantic function (e.g. declaring a function pointer), they don’t just group. cppreference has an example illustrating this:
new int(*[10])(); // error: parsed as (new int) (*[10]) ()
new (int (*[10])()); // okay: allocates an array of 10 pointers to functions
Furthermore, the syntax for writing type declarations (inherited from C) works in outwards-directed clockwise spirals. Note that the variable you want to allocate storage for is declared as
int (*matrix)[nCols]
The variable is the innermost part. And, lastly, pointer access in C (and C++) mirrors pointer declaration. Therefore, the new[] expression mirrors the declaration syntax and, since you want to allocate nRow static arrays, the number of elements you are allocating is dropped into the position of the pointer declaration ((*matrix)).
I advise against writing such code in C++. First off, use constexpr instead of const here, although in this particular case bare const remains valid.
But more importantly, you almost(?) never want to use new. Instead of manually allocating an array, use std::vector:
std::vector<int[nCols]> matrix(nRows);
// or:
std::vector<std::array<int, nCols>> matrix(nRows);

It's to be consistent with an ordinary array declaration and array indexing.
Note T array[M][N]; also declares an array of M arrays, each with size N, just like what's created by new T[M][N].
Now think about the expression a[i][j], where a is either an array of M arrays, each with size N, or a pointer to the first array element in such an array:
extern int a[M][N];
// OR
extern int b[M][N];
int (*a)[N] = b;
// OR
int (*a)[N] = new int[M][N];
To evaluate a[i][j], we first apply subscript i, then subscript j. This just makes sense from the order they appear, plus the expression parses as (a[i])[j]. The subexpression a[i] will be the i-th subarray of type int[N], so i may range from 0 to M-1. Once we have that subarray, the valid j indices are from 0 to N-1. So to make the order of the indices match up with the array declaration or new syntax, the language chooses to specify them so that the "top-level" dimension is first: T[M][N] means "array of M arrays of N objects of type T".
Yes, this does mean things may be a bit surprising when using a type alias: if ArrT is T[X], then ArrT[Y] is T[Y][X]. But type aliases definitely don't work like text substitutions anyway (for another example, if Ptr is int*, const Ptr is int *const and not const int*).

Related

Error: cannot convert ‘std::string (*)[3]' to ‘std::string** in return [duplicate]

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?
Why does int*[] decay into int** but not int[][]?
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:
6.18: My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer.
6.19: How do I write functions which accept two-dimensional arrays when the width is not known at compile time?
6.20: How can I use statically- and dynamically-allocated multidimensional arrays interchangeably when passing them to functions?
(This is all for C, but this behaviour is essentially unchanged in C++.)
C was not really "designed" as a language; instead, features were added as needs arose, with an effort not to break earlier code. Such an evolutionary approach was a good thing in the days when C was being developed, since it meant that for the most part developers could reap the benefits of the earlier improvements in the language before everything the language might need to do was worked out. Unfortunately, the way in which array- and pointer handling have evolved has led to a variety of rules which are, in retrospect, unfortunate.
In the C language of today, there is a fairly substantial type system, and variables have clearly defined types, but things were not always thus. A declaration char arr[8]; would allocate 8 bytes in the present scope, and make arr point to the first of them. The compiler wouldn't know that arr represented an array--it would represent a char pointer just like any other char*. From what I understand, if one had declared char arr1[8], arr2[8];, the statement arr1 = arr2; would have been perfectly legal, being somewhat equivalent conceptually to char *st1 = "foo, *st2 = "bar"; st1 = st2;, but would have almost always represented a bug.
The rule that arrays decompose into pointers stemmed from a time when arrays and pointers really were the same thing. Since then, arrays have come to be recognized as a distinct type, but the language needed to remain essentially compatible with the days when they weren't. When the rules were being formulated, the question of how two-dimensional arrays should be handled wasn't an issue because there was no such thing. One could do something like char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5); and then use bar[x][y] in the same way as one would now use a two-dimensional array, but a compiler wouldn't view things that way--it just saw bar as a pointer to a pointer. If one wanted to make foo[1] point somewhere completely different from foo[2], one could perfectly legally do so.
When two two-dimensional arrays were added to C, it was not necessary to maintain compatibility with earlier code that declared two-dimensional arrays, because there wasn't any. While it would have been possible to specify that char bar[4][5]; would generate code equivalent to what was shown using the foo[20], in which case a char[][] would have been usable as a char**, it was thought that just as assigning array variables would have been a mistake 99% of the time, so too would have been re-assignment of array rows, had that been legal. Thus, arrays in C are recognized as distinct types, with their own rules which are a bit odd, but which are what they are.
Because int[M][N] and int** are incompatible types.
However, int[M][N] can decay into int (*)[N] type. So the following :
std::is_same<int(*)[1], std::decay<int[1][1]>::type>::value;
should give you true.
Two dimensional arrays are not stored as pointer to pointers, but as a contiguous block of memory.
An object declared as type int[y][x] is a block of size sizeof(int) * x * y whereas, an object of type int ** is a pointer to an int*

C++ array sizes without constant expressions

I'm reading Stroustrup's A Tour of C++. On page 9, he states:
"The size of an array must be a constant expression."
Yet later, on pg. 16, he uses the following code sample:
void vector vector_init(Vector& v, int s)
{
v.elem = new double[s]; // Allocate an array of s doubles
v.sz = s;
}
Here s is not a constant expression, so how is initializing v.elem to new double[s] legal?
There is a differentiation between allocated arrays (i.e. those created with a new[] expression, like new double[s]), whose lifetimes must be managed by the code (via delete[]) and declared arrays, whose lifetimes are managed by their scope alone:
int* p = new int[s]; // allocated array, p has type int*
int q[10]; // declared array, q has type int[10]
std::vector<int> u; // has member allocated array
std::array<int, 5> v; // has member declared array
The differentiation is not based on stack/heap. A declared array can be heap allocated (e.g. new array<int,5>) or not on the stack (e.g. static double x[100];)
With an allocated array, the size does not have to be a constant expression. The size will simply be encoded into the block of memory yielded by the allocator somehow (for instance the four leading bytes before the actual data starts) so that the corresponding delete[] knows how many elements to delete.
With a declared array (or non-allocated array, no new/malloc/etc.), the size must† be coded into the type, so that the destructor knows what to do. The only allowed, standard array declaration is:
T D[constant-expression_opt];
(where D is a declarator that could be a name or another array declaration, etc.) Declared arrays are not limited to the stack. Note that, for added confusion, the constant-expression is optional.
Arrays offer many sources of confusion in C++. Allocated and declared arrays have different size rules, different management practices, but you can assign a T* to either and they're equivalently indexed. An allocated array is a pointer (that's all you get), but a declared array decays to a pointer (but is an array!).
†Note that there is a concept of a Variable Length Array (VLA). gcc, for instance, supports them as an extension, but they are non-standard C++. It gets periodically proposed though, and you can see this question for more information about them.
When creating an array whose memory is managed by compiler, its size must be (compile time) constant. For ex:
int a[5];
const int sz = 7;
int b[sz] = {0};
(Some languages for ex: C (C99 onwards) support dynamic array size)
If you want a dynamically sized array (Example snippet given by you), you need to allocate memory for it by yourself you'll also need to free it with delete when you're done. Size of such arrays can be non-const also. Moreover you need to manage the memory by yourself, allocation may fail and operators (for example sizeof) would operate on the pointer rather than array.
In modern C++ (C++11 onwards), even stl container std::array must have a constant size.
The quote
The size of an array must be a constant expression.
is talking about an array declaration, such as
double a[EXPR];
where EXPR must indeed be a constant or constexpr (C has variable-length arrays, but they're not part of standard C++).
The expression you mention as a counter-example,
new double[s]
is not an array, despite the []. It is a new-expression, and yields a pointer, not an array. You didn't show the definition of v.elem, but I can tell it's a pointer-to-double.
Note from the linked discussion on new expressions that
If type is an array type, all dimensions other than the first must be specified as positive {something like an integral constant - detail elided}.
So the type referred to above is double[s], which is explicitly allowed.
Admittedly the difference between an array, and the array type passed to a new expression is a little subtle, but you can't conflate them just because of the [], any more than you can claim that
map["key"]
violates something by declaring an array with length "key".

What is the type of new int[M][N]?

According to typeid(array).name() it is PAN_i in G++ 4.8.4. I know P means pointer and i means int, but what type is A and why is there only second dimension - N - and not the first - M.
What should I type instead of auto in auto array = new int[M][N]?
Is there a way to assign array to int**?
Another issue is M and N must be compile-time constants. If they are not, I guess my only option is the dynamic C++03 2D arrays.
What is the type of new int[M][N]?
The type is pointer to length N array of int1, or
int (*)[N]
If you think of what a new[] expression does, it initializes an array of a length given at runtime and returns a pointer to the first element of that array. So the type of
new T[M]
is T*. In the 2D case, you can think of T as being int[N]. So each element of the array is a itself array, and new returns a pointer to its first element. This may be a clearer way of expressing it:
typedef int ArrayN[N];
auto array = new ArrayN[M];
1 And in C++, the dimensions if C-style arrays have to be compile time constants, meaning N has to be a constant expression

Pointer to array and errors C2057, C2540

I want to do something like:
const int N = 10;
void foo (const int count)
{
int (* pA) [N][count] = reinterpret_cast<int(*)[N][count]>(new int[N * count]);
...
}
But my compiler (VS2010) doesn't want to do it:
error C2057: expected constant expression
error C2540: non-constant expression as array bound
Such a way he expresses his dissatisfaction with the count.
I know, how it can be worked around by implementing a slightly different way. But I just don't get, why does C++ forbid me to use this way. I understand, why C++ needs to know on-stack arrays size at compile time (to allocate array memory). But why the same restrictions are necessary with respect to pointers to array (after all, pointer is just a tool to work with that allocated memory)?
Well, actually what you want is in principle alright, but you're using the wrong syntax.
All dimensions except the first have to be compile-time constants, because they're used in pointer arithmetic. The first one can be runtime varying. This works:
int (* pA)[N] = new int[count][N];
Remember that an array is compatible with pointer-to-element-type, and subscripting works exactly the same on both. So when you have a 2-D array allocated (array of arrays), you should store a pointer-to-1D-array.
There's no way to do int[N][count], though, because that would need an array of elements (subarrays) of variable size.
Furthermore, note that N is a constant-expression, but count is not. Even though they both have the same type, count is a parameter, determined at runtime.
If you want to accept a constant integral expression as an argument, make it a template argument:
template <int count>
void foo()
Now count is a constant expression just like N.

Why does int*[] decay into int** but not int[][]?

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?
Why does int*[] decay into int** but not int[][]?
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:
6.18: My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer.
6.19: How do I write functions which accept two-dimensional arrays when the width is not known at compile time?
6.20: How can I use statically- and dynamically-allocated multidimensional arrays interchangeably when passing them to functions?
(This is all for C, but this behaviour is essentially unchanged in C++.)
C was not really "designed" as a language; instead, features were added as needs arose, with an effort not to break earlier code. Such an evolutionary approach was a good thing in the days when C was being developed, since it meant that for the most part developers could reap the benefits of the earlier improvements in the language before everything the language might need to do was worked out. Unfortunately, the way in which array- and pointer handling have evolved has led to a variety of rules which are, in retrospect, unfortunate.
In the C language of today, there is a fairly substantial type system, and variables have clearly defined types, but things were not always thus. A declaration char arr[8]; would allocate 8 bytes in the present scope, and make arr point to the first of them. The compiler wouldn't know that arr represented an array--it would represent a char pointer just like any other char*. From what I understand, if one had declared char arr1[8], arr2[8];, the statement arr1 = arr2; would have been perfectly legal, being somewhat equivalent conceptually to char *st1 = "foo, *st2 = "bar"; st1 = st2;, but would have almost always represented a bug.
The rule that arrays decompose into pointers stemmed from a time when arrays and pointers really were the same thing. Since then, arrays have come to be recognized as a distinct type, but the language needed to remain essentially compatible with the days when they weren't. When the rules were being formulated, the question of how two-dimensional arrays should be handled wasn't an issue because there was no such thing. One could do something like char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5); and then use bar[x][y] in the same way as one would now use a two-dimensional array, but a compiler wouldn't view things that way--it just saw bar as a pointer to a pointer. If one wanted to make foo[1] point somewhere completely different from foo[2], one could perfectly legally do so.
When two two-dimensional arrays were added to C, it was not necessary to maintain compatibility with earlier code that declared two-dimensional arrays, because there wasn't any. While it would have been possible to specify that char bar[4][5]; would generate code equivalent to what was shown using the foo[20], in which case a char[][] would have been usable as a char**, it was thought that just as assigning array variables would have been a mistake 99% of the time, so too would have been re-assignment of array rows, had that been legal. Thus, arrays in C are recognized as distinct types, with their own rules which are a bit odd, but which are what they are.
Because int[M][N] and int** are incompatible types.
However, int[M][N] can decay into int (*)[N] type. So the following :
std::is_same<int(*)[1], std::decay<int[1][1]>::type>::value;
should give you true.
Two dimensional arrays are not stored as pointer to pointers, but as a contiguous block of memory.
An object declared as type int[y][x] is a block of size sizeof(int) * x * y whereas, an object of type int ** is a pointer to an int*