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