[comp.std.c++] X3j16 "contractions"

jgro@lia (Jeremy Grodberg) (03/30/91)

I'd like to add to the list of contractions the "feature" that a class'
overloaded operator new is not called when allocating an array of
class objects.  This "feature" eliminates any clean way of handling, or
prohibiting, arrays of classes in situations where you want to do your
own memory allocation (or reference count, or debug tracing, or whatever).


-- 
Jeremy Grodberg      "Show me a new widget that's bug-free, and I'll show
jgro@lia.com         you something that's been through several releases."

wmm@world.std.com (William M Miller) (03/31/91)

jgro@lia (Jeremy Grodberg) writes:
> I'd like to add to the list of contractions the "feature" that a class'
> overloaded operator new is not called when allocating an array of
> class objects.  This "feature" eliminates any clean way of handling, or
> prohibiting, arrays of classes in situations where you want to do your
> own memory allocation (or reference count, or debug tracing, or whatever).

While I agree that some features might best be removed, this is not one of
them.

There are basically two arguments against calling X::operator new() for an
array of X.  The first is that an array of X is not a user-defined type, any
more than a pointer to X is; arrays and pointers are built-in types, and you
can't overload on built-in types (at least until/unless we adopt operator.()
:-).

If that philosophical point doesn't convince you, the pragmatic argument is
that the biggest use of operator new() is to reduce the cost of storage
allocation when some feature (typically constant size) of the object being
allocated allows the programmer to do a smarter job than is possible for the
general-purpose allocator.  If operator new() had to worry about arbitrary-
sized arrays instead of just fixed-size individual objects, the job of
writing operator new() would become more complex and dangerous.  (Okay,
admittedly it's just the addition of a couple of lines of code like,

        if (size != sizeof(X))
           return ::operator new(size);

But if you forgot to write that -- and don't forget that there are by now
thousands of operator new()s already written that *don't* have that code --
you have written *very* unsafe code; if it's ever used to allocate an array,
you're guaranteed to go tromping through unowned memory.)

Back to the philosophical side of things, C-style arrays are a very
low-level kind of data structure.  If you really want to do fancy things
like reference counting, debug tracing, and the like, you ought to write
your own Array container class and use it instead of plain vanilla arrays;
it's not hard, and C++ gives you all the features you need to do so.

-- William M. Miller, Glockenspiel, Ltd.
   wmm@world.std.com

horstman@mathcs.sjsu.edu (Cay Horstmann) (04/01/91)

In article <1991Mar30.065943.3074@lia> jgro@lia.com (Jeremy Grodberg) writes:
>I'd like to add to the list of contractions the "feature" that a class'
>overloaded operator new is not called when allocating an array of
>class objects.  This "feature" eliminates any clean way of handling, or
>prohibiting, arrays of classes in situations where you want to do your
>own memory allocation (or reference count, or debug tracing, or whatever).
>
I wouldn't call this a contraction of the language, but...

It would indeed be desirable if the class user could also control allocation
of arrays (or defer to ::operator new if the allocator isn't prepared to
handle arrays, e.g. if the allocator doles out fixed-size blocks in lifo
fashion). 

The natural way of doing that is to tinker with operator new and have the
compiler call X::operator new( size_t, size_t, ... ) when an array of X's
is allocated. 

This has the odd effect that calls 
	X* px = new X[n];
and
	X* px = new(n) X;
have the same result. But that is probably ok.

I realize that RIGHT NOW one could tell one's class users to allocate
arrays of X's using the second statement. But "telling the class user"
isn't usually great programming strategy. In particular, it isn't invariant
under change of allocation scheme ("since I just changed the allocation of
X's, please change all new X[n] to new(n) X").

Cay

daniel@terra.ucsc.edu (Daniel Edelson) (04/01/91)

In article <1991Mar31.164628.14033@mathcs.sjsu.edu> horstman@mathcs.sjsu.edu (Cay Horstmann) writes:
>In article <1991Mar30.065943.3074@lia> jgro@lia.com (Jeremy Grodberg) writes:
>>I'd like to add to the list of contractions the "feature" that a class'
>>overloaded operator new is not called when allocating an array of
>>own memory allocation (or reference count, or debug tracing, or whatever).
>
>It would indeed be desirable if the class user could also control allocation
>of arrays (or defer to ::operator new if the allocator isn't prepared to
>handle arrays,....

>The natural way of doing that is to tinker with operator new and have the
>compiler call X::operator new( size_t, size_t, ... ) when an array of X's
>is allocated. 

>Cay

This is not the natural way of doing that. 
That is a poor way of doing it because it makes allocation of an
array indistinguishable from allocation of a scalar with an extra argument
to new of type size_t. 

A somewhat more natural way is to use another operator, e.g., ``vec_new'', 
for allocation of arrays.
The operator could take two arguments, a size_t and an unsigned.
However, I haven't considered the ramifications of this for
multidimensional arrays.

You almost need to support variable arguments. One tells the number
of dimensions and the others are the sizes in each dimension.

Perhaps ``vec_new()'' should take:

	void * T::vec_new(size_t obj_size, int ndims, unsigned sizes[])
	{
		...
	}

Where ndims is the number of dimensions in the array and sizes
is an array of the size in each dimension.

Hmm.

daniel