[comp.lang.c++] Questions about new and array definitions

mhyman@hsfmsh.uucp (Marco S. Hyman) (03/08/90)

A co-worker came up with a problem that brings up an interesting C++
question.  He wanted to create a pointer to an array of void pointers.
The definition he used was:

	void * (*a)[];

In the constructor of the class `a' was defined in he tried to allocate
memory using

	a = new (void *)[size];  // size was passed to the constructor

Cfront complained with the error:

	error: bad assignment type: void *(*)[] = void *

When the problem came to me I first tried some things to see if I could
get memory allocated for `a' as defined.  Things tried were

	a = new void *(*)[size];
	error: syntax error

	a = new (void *(*)[size]);
	error: bad assignment type: void *(*)[] = void *(**)[size]

	a = new void **[size];
	error: bad assignment type: void *(*)[] = void **[size]

After several tries I came up with something cfront liked

	a = new (void *(*)[])[size];

The problem is that the code generated was not what was expected.  Memory
was allocated for one void pointer; size was not part of the allocation
equation.  The generated code looked like (cleaned up for easier reading):

	this->a = (((char *(**)[]) __nw__FUi(sizeof(char *(*)[]))))[size];

The solution was, of course, to get the [] out of the definition and use

	void ***a;

	a = new void **[size];

What is void * (*)[] then?  Is there a way to allocate memory for it using
new?

// marc

mhyman@hsfmsh.uucp (Marco S. Hyman) (03/09/90)

There are some differences between Zortech and cfront in the use of new
with array definitions.  This, from a co-worker [[with my comments like
this]], shows the differences.  Which is right?

----------------------------
I saw your message on USENET. Something didn't seem exactly the same
as what I did, so I ran your examples through the Zortech compiler.
As I suspected, the results I got were different (but not substantially,
except in first case) from those with CFront:

// Base class definition -- doesn't change.

class F
{
   void *   (*a)[];

public:

   F( int size );

};

First constructor compiles, but generates the wrong code. Allocates one
void *, then tries to dereference with [size]. Odd that Cfront didn't like
this one at all:

F::F( int size )
{
   a = new (void *)[size];       // case 1
}

Second constructor doesn't compile:

F::F( int size )
{
   a = new void *(*)[size];      // case 2
                   ^
"test2.cpp", line 13 Syntax error: expression expected

}

Third doesn't compile:

F::F( int size )
{
   a = new (void *(*)[size]);    // case 3
                          ^
"test3.cpp", line 13 Syntax error: integer constant expression expected

}

Forth constructor. This works! Without changing the base definition 
of the array a! I think it is because a[] and (*a)[] are considered
identical to C. (consider that an array is known by the pointer to its
first element!)

F::F( int size )
{
   a = new void **[size];        // case 4
}

[[This does not work with cfront unless the definition of a is changed to
void ***a; cfront give a type match error]]

Fifth constructor. Compiles, but generates the same code as case 1.

F::F( int size )
{
   a = new (void *(*)[])[size];  // case 5
}

There were other variations I tried in a vain attempt to get this
business to work, but I can't remember them all. Suffice it to say
that the designers of C++ sure made the good old process of
a = malloc( size * sizeof(void *) ) and made it much too obfuscated
in an attempt to make it type-safe. 

You can post this, if you like.

   Bill Coleman
-------------------------------------

If you'd like to respond to Bill use one of the following addresses.

	hsfmsh!bcoleman-vax@sfsun.west.sun.com
	...!hoptoad!hsfmsh!bcoleman-vax

// marc