[comp.std.c++] Order of fields within one section

miron@fornax.UUCP (Miron Cuperman) (08/16/90)

Is the order of fields within a section preserved?
For example:
class C
{
private:
	int size;
	float a[0];
}

Is 'a' guaranteed to be after size so I can do
	C *C1=malloc(sizeof(C)+n*sizeof(float));

If that is permissible, is it possible to use 'new' to allocate
an arbitrarily sized object?
-- 
	By me: Miron Cuperman <miron@cs.sfu.ca>

perry@key.COM (Perry The Cynic) (08/18/90)

In article <1083@fornax.UUCP> miron@fornax.UUCP (Miron Cuperman) writes:
> Is the order of fields within a section preserved?
> For example:
> class C
> {
> private:
> 	int size;
> 	float a[0];
> }
> 
> Is 'a' guaranteed to be after size so I can do
> 	C *C1=malloc(sizeof(C)+n*sizeof(float));
> 
> If that is permissible, is it possible to use 'new' to allocate
> an arbitrarily sized object?

The order of fields within a section is guaranteed to be preserved by the
compiler (says E&S). You are guaranteed that "a" follows "size" in the
storage layout of the class. But that doesn't help you.

The compiler is perfectly entitled to place stuff *after* a[0] (there is an
explicit warning to that effect in E&S) If class C has virtual members, you
have a good chance that some compiler out there (perhaps yours) will put its
virtual table pointer at the end of the class, totally screwing up your scheme.
This is not portable C++, nor is it good C++, though it is a common practice
in the C world.

One possible solution is to change your class definition into
	class C {
	public:
		C(int n);
	private:
		int size;
		float *a;
	};

	C::C(int n) {
		a = new float[n];
	}
which is (I hope) perfectly portable. You can add appropriate access functions
to your class (including, if you wish, a float& operator[]).
Depending on your particular situation, you may then be able to allocate objects
of type C as static or auto variables, or members of other structures. If you
can do that, performance will actually be improved (because accesses to the
size member don't need indirection). This requires a somewhat different way
to look at C objects (value-oriented vs. reference-oriented), but I find it
to be rather useful.
  -- perry
-- 
--------------------------------------------------------------------------
Perry The Cynic (Peter Kiehtreiber)		       perry@arkon.key.com
** What good signature isn't taken yet? **  {amdahl,sgi,pacbell}!key!perry

jimad@microsoft.UUCP (Jim ADCOCK) (08/18/90)

In article <1083@fornax.UUCP> miron@fornax.UUCP (Miron Cuperman) writes:
>Is the order of fields within a section preserved?

Yes.  According to E&S.  But, "preserved" only means that fields declared later
within a section come at higher addresses.   "Preserved" doesn't mean that
fields are adjecent, nor that they don't have anything else useful between
them, nor that they have the same packing characteristics as your favorite
C compiler.  [Although I'd certainly think that most vendors would want to
keep their C and C++ compilers pretty compatible for the next couple of 
years as people switch over.]

But, I'm lobbying to have this restriction eased so that C++ compilers aren't
constrained to be backwardly compatible with C a couple years down the road --
when backwards compatibility is no longer an issue.  And again, in any case,
for a C and a C++ compiler to be "compatible" a vendor is going to have
to make a conscious decision they want their C and C++ compilers to be 
compatible.  Field ordering is only a tiny part of this decision.  Removing
field ordering restrictions doesn't keep a vendor from making their C and
C++ compilers compatible.  Maintaining field ordering doesn't force a vendor
to keep their C and C++ compilers compatible.  In either case, its still
strictly an particular vendor's choice.  So I say, let's remove this silly 
restriction.

>For example:
>class C
>{
>private:
>	int size;
>	float a[0];
>}

No -- Array dimensions must be specified as being greater than zero.

>Is 'a' guaranteed to be after size 

Yes -- but "after" just means that a has a higher address than size,
not that they are next to each other.  And what it means to compare addresses 
of different types of things is also undefined.  So what does it mean to
be able to say a is "after" size ?

so I can do C *C1=malloc(sizeof(C)+n*sizeof(float));

Yes and No.  Yes such a statement is legal in the language.  But, no
it is not legal to then use C1 as you're planning to use it.  E&S 
specifically calls out the old C trick of writing off the end of a 
structure as being illegal.  [It was never even legal to write off the end of
an array in C]

Most C++ compilers today would generate code incompatible with this
hack if someone subsequently tries to derive from class C.

>If that is permissible, is it possible to use 'new' to allocate
>an arbitrarily sized object?

"That" is not "legal" --but is it "permissible"?  Most C++ compilers will permit
you to get away with it [given your array index is not zero.]  Just don't
try to derive from C, nor make an instance static, nor put an instance
on the stack....

....The obvious hack is to get a chunk of memory from new:

void *pv = new char[sizeof(C) + n*sizeof(float)]; // give or take one from n

then construct your object at the start of that chunk using placement
syntax:

C* C1 = new(pv) C(n);

---

Better yet, just don't do this hack, use a separate allocation for your array.