Quirk in new allocations

M

mooingpsychoduck

Someone online (http://stackoverflow.com/q/17091991/845092) was trying to initialize a variable like so:

int (**a)[10] = new [10][20][30];

And (regardless of what he _actually_ wanted), I quickly discovered that without a typedef I could initialize "a" to (a dynamic pointer to a (pointer to (an array of ten integers))), but without a typedef I could NOT initialize "a" to (a dynamic array of 30 (pointers to (an array of ten integers))).Succinctly:

//this line compiles fine
int (**a)[10] = new (int (*)[10]);
//error: array bound forbidden after parenthesized type-id
int (**a)[10] = new (int (*)[10])[30];

Is there a trick to this I haven't thought of, or is it actually impossibleto do this without a typedef? One can easily use typedefs, or type deduction, or any number of other tricks as a workaround, but I was surprised that I could not do this as a "basic" expression.

(Please don't speculate new expressions that you think might work without testing them in a compiler first. My friends and I have already tested many permutations. Random guesses are not going to be helpful here.)
 
V

Victor Bazarov

Someone online (http://stackoverflow.com/q/17091991/845092) was trying to initialize a variable like so:

int (**a)[10] = new [10][20][30];

A type is missing somewhere in the right-hand side of that assignment sign.
And (regardless of what he _actually_ wanted), I quickly discovered
that without a typedef I could initialize "a" to (a dynamic pointer to a
(pointer to (an array of ten integers))), but without a typedef I could
NOT initialize "a" to (a dynamic array of 30 (pointers to (an array of
ten integers))). Succinctly:
//this line compiles fine
int (**a)[10] = new (int (*)[10]);
//error: array bound forbidden after parenthesized type-id
int (**a)[10] = new (int (*)[10])[30];

Is there a trick to this I haven't thought of, or is it actually
impossible to do this without a typedef? One can easily use typedefs, or
type deduction, or any number of other tricks as a workaround, but I was
surprised that I could not do this as a "basic" expression.
(Please don't speculate new expressions that you think might work
without testing them in a compiler first. My friends and I have already
tested many permutations. Random guesses are not going to be helpful here.)

Were you trying to allocate a multidimensional array in one call to
'new'? I don't think it's possible. You can allocate 6000 integers in
one call and probably use the placement new to "map" it to an array of
30 arrays of 20 arrays of 10 integers. But it's not the same thing, I
suppose.

Perhaps something like this:

int (*p)[10][20] = new (std::nothrow) (int(*)[10][20])[30];


V
 
B

Bart van Ingen Schenau

I quickly discovered that
without a typedef I could initialize "a" to (a dynamic pointer to a
(pointer to (an array of ten integers))), but without a typedef I could
NOT initialize "a" to (a dynamic array of 30 (pointers to (an array of
ten integers))). Succinctly:

//this line compiles fine
int (**a)[10] = new (int (*)[10]);
//error: array bound forbidden after parenthesized type-id int
(**a)[10] = new (int (*)[10])[30];

Is there a trick to this I haven't thought of, or is it actually
impossible to do this without a typedef? One can easily use typedefs,
or type deduction, or any number of other tricks as a workaround, but I
was surprised that I could not do this as a "basic" expression.

It is possible to declare an array of 30 pointers to arrays of 10 int
using only "basic" expressions, but you need a good grasp on the
declaration syntax to get it done.
For such complex declarations, it is best to start out with writing it
for a regular variable:

int (*bar[30])[10];

then you can take out the variable name, and you have the type to use in
the new expression:

a = new (int (*[30])[10]);

Bart van Ingen Schenau
 
J

James Kanze

Someone online (http://stackoverflow.com/q/17091991/845092) was trying to
initialize a variable like so:
int (**a)[10] = new [10][20][30];

A type is missing somewhere in the right-hand side of that assignment sign.
And (regardless of what he _actually_ wanted), I quickly discovered that
without a typedef I could initialize "a" to (a dynamic pointer to a
(pointer to (an array of ten integers))), but without a typedef I could NOT
initialize "a" to (a dynamic array of 30 (pointers to (an array of ten
integers))). Succinctly:
//this line compiles fine
int (**a)[10] = new (int (*)[10]);
//error: array bound forbidden after parenthesized type-id
int (**a)[10] = new (int (*)[10])[30];
Is there a trick to this I haven't thought of, or is it actually
impossible to do this without a typedef? One can easily use typedefs, or
type deduction, or any number of other tricks as a workaround, but I was
surprised that I could not do this as a "basic" expression.

I'm surprised that anyone would want to do this. I *think* the
correct expression for the new would be "new (int (*[30])[10])",
but this gives me an error message to the effect that lambda
expressions are only available with the option -std=c++0x.
Since there's clearly no lambda expression in the new
expression, there is an error in the compiler. Whether this
error is just an incorrect message or not, is difficult to say;
unless I've missed something, the expression I give requests 30
pointers to an array of 10 int, which should decay to a pointer
to a pointer to 10 int.

Reading the standard is. Of course, if there is a bug in your
compiler, that won't help you. And a bug in the compiler in
this case wouldn't surprise me (regardless of which compiler you
use); the expression is extremely complex, and not the sort of
thing any reasonable programmer would use (which means that the
code to correctly evaluate it may never have been tested).
Were you trying to allocate a multidimensional array in one call to
'new'? I don't think it's possible. You can allocate 6000 integers in
one call and probably use the placement new to "map" it to an array of
30 arrays of 20 arrays of 10 integers. But it's not the same thing, I
suppose.

It's very easy to allocate a multidimensional array in one call
to new, provided you use the correct types:

int (*array)[20][30] = new int[10][20][30];

In general, however, I would consider this more or less bad
style; far better would be to define a class Matrix3D, and use
a simple std::vector said:
Perhaps something like this:
int (*p)[10][20] = new (std::nothrow) (int(*)[10][20])[30];

I'm curious about your use of placement new here.

int (**a)[10] = new (std::nothrow) (int (*[30])[10]);

does compile with my compiler, but I would argue that this only
prooves that the failure to compile I describe above is an error
in the compiler: the syntax for "(type-id)" in the new
expression is exactly the same regardless of whether you use
placement new or not. (Of course, whether the expression does
what the OP wants or expects is another question. He's still
only getting an array of pointers, not a multidimensional array.)
 
8

88888 Dihedral

James Kanzeæ–¼ 2013å¹´6月17日星期一UTC+8上åˆ1時25分53秒寫é“:
On 6/13/2013 2:12 PM, (e-mail address removed) wrote:
Someone online (http://stackoverflow.com/q/17091991/845092) was trying to
initialize a variable like so:
int (**a)[10] = new [10][20][30];
A type is missing somewhere in the right-hand side of that assignment sign.
And (regardless of what he _actually_ wanted), I quickly discovered that
without a typedef I could initialize "a" to (a dynamic pointer to a
(pointer to (an array of ten integers))), but without a typedef I could NOT
initialize "a" to (a dynamic array of 30 (pointers to (an array of ten
integers))). Succinctly:

//this line compiles fine
int (**a)[10] = new (int (*)[10]);
//error: array bound forbidden after parenthesized type-id
int (**a)[10] = new (int (*)[10])[30];

Is there a trick to this I haven't thought of, or is it actually
impossible to do this without a typedef? One can easily use typedefs,or
type deduction, or any number of other tricks as a workaround, but I was
surprised that I could not do this as a "basic" expression.



I'm surprised that anyone would want to do this. I *think* the

correct expression for the new would be "new (int (*[30])[10])",

but this gives me an error message to the effect that lambda

expressions are only available with the option -std=c++0x.

Since there's clearly no lambda expression in the new

expression, there is an error in the compiler. Whether this

error is just an incorrect message or not, is difficult to say;

unless I've missed something, the expression I give requests 30

pointers to an array of 10 int, which should decay to a pointer

to a pointer to 10 int.





Reading the standard is. Of course, if there is a bug in your

compiler, that won't help you. And a bug in the compiler in

this case wouldn't surprise me (regardless of which compiler you

use); the expression is extremely complex, and not the sort of

thing any reasonable programmer would use (which means that the

code to correctly evaluate it may never have been tested).


Were you trying to allocate a multidimensional array in one call to
'new'? I don't think it's possible. You can allocate 6000 integers in
one call and probably use the placement new to "map" it to an array of
30 arrays of 20 arrays of 10 integers. But it's not the same thing, I



It's very easy to allocate a multidimensional array in one call

to new, provided you use the correct types:



int (*array)[20][30] = new int[10][20][30];



In general, however, I would consider this more or less bad

style; far better would be to define a class Matrix3D, and use

a simple std::vector<int> in the implementation of the class.


Perhaps something like this:


int (*p)[10][20] = new (std::nothrow) (int(*)[10][20])[30];



I'm curious about your use of placement new here.



int (**a)[10] = new (std::nothrow) (int (*[30])[10]);



does compile with my compiler, but I would argue that this only

prooves that the failure to compile I describe above is an error

in the compiler: the syntax for "(type-id)" in the new

expression is exactly the same regardless of whether you use

placement new or not. (Of course, whether the expression does

what the OP wants or expects is another question. He's still

only getting an array of pointers, not a multidimensional array.)

Indexing a 3D array elelment in any RW operation requires
2 multiplications, but the pointer version is different.

It does not matter in small sizes under 1M elements nowadays.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top