rpk@rice-chex.ai.mit.edu (Robert Krajewski) (09/13/90)
Does anybody else consider the fact that new[] only works with default constructors (i.e., those with no parameters) to be a blemish on the language ? If you spend some time generate a nice simple consistent class, and then discover you need to use new[], you have to then go and implement modification operations that may be have been unneccessary before. There are workarounds, I realize, like writing your own loop and using operator new (size_t, void *). Basically, I don't buy the argument in the bulletted item on page 61 of E&S (section 5.3.3). The compiler can easily generate correct and efficient initialization code for this case where parameters are passed. The only decision to be made is how many times the arguments to a constructor are evaluated in such a context. Robert P. Krajewski Internet: rpk@ai.mit.edu ; Lotus: robert_krajewski.lotus@crd.dnet.lotus.com
pcg@cs.aber.ac.uk (Piercarlo Grandi) (09/16/90)
On 12 Sep 90 17:57:01 GMT, rpk@rice-chex.ai.mit.edu (Robert Krajewski) said: rpk> Does anybody else consider the fact that new[] only works with rpk> default constructors (i.e., those with no parameters) to be a rpk> blemish on the language ? [ ... ] I think that the special treatment of arrays by operator new is the big blemish. The problem here is really that operator new really should allocate a single object; if you use cast like parenthesization of abstract declarators, you see that in typedef c100 complex[100]; complex *c1 = new complex[100]; complex *c2 = new c100; complex *c3 = new (complex[100]); the last three lines *should be* exactly equivalent, and essentially equivalent in turn to the last two lines of extern "C" extern void *malloc(size_t); complex *c4 = (complex *) malloc(sizeof (complex[100])); complex *c5 = (complex *) malloc(sizeof (c100)); because 'c100' is not a class type and therefore has no constructors or destructors. rpk> There are workarounds, I realize, like writing your own loop and rpk> using operator new (size_t, void *). This is not a workaround; it is a proper use of the abstraction facilities of C++. A strict interpretation like mine above would mean that users should be made to define their own array type constructors; in other words, users should make the 'c100' type explicit as a class, with a suitable constructor to initialize each element, e.g. something like #include <complex.H> class cv { protected: const unsigned n; complex *c; public: cv(unsigned /* add further parameters as desired */); ~cv(); inline complex &operator[](unsigned); // ..... }; #include <assert.H> // Under C++ 2.1 the static below regrettably is out static inline complex &cv::operator[](auto const unsigned i) { assert (i >=0 && i < this->n,"cv::operator[]"); return &this->c[i]; } extern "C" extern void *calloc(size_t,unsigned); extern "C" extern void free(void *); extern cv::cv(auto const unsigned e /* any other parameters */) : n(e), c(calloc(sizeof (complex),e)) { register complex *c; register complex *const l = &this->c[e]; assert (this->c != 0,"cv::cv"); for (c = &this->c[0]; c < l; c++) (void) new((void *) c) (complex)(/* any other parameters */); } extern cv::~cv() { register complex *c; register complex *const l = &this->c[e]; for (c = &this->c[0]; c < l; c++) c->~complex(); free((void *) c); } // ... and so on merrily In the absence of templates, this has been deemed too boring for users to do for each type of array they want (even if you can get a lot of mileage out of macros and using 'void *' and horrible pointer arithmetic), so operator new does a special case for arrays, leading to all that silly square bracketing with operator delete. Note that C++ 2.1 seems to imply that the above is more or less how the compiler is required to implement heap arrays now. Uhm. rpk> Basically, I don't buy the argument in the bulletted item on page rpk> 61 of E&S (section 5.3.3). The compiler can easily generate rpk> correct and efficient initialization code for this case where rpk> parameters are passed. The fundamental problem is that C++ inherits from C a weak definition of arrays and the array type constructor, one that seems to be unacceptable to users of C++ (which seem to require a definition of arrays that implies keeping descriptors at run time); attempts to patch this definition up so that it meets the expectation of C++ users without jettisoning the C one altogether have caused quite a bit of confusion. My idea: if the C++ users want arrays that behave like classes, let them define their own array classes, and when they will have templates, they can define just one template for each array arity. XOR, junk the conventional C idea of the array type constructor, and provide a C++-ish one. Halfway you basically get mostly trouble. Incidentally, making the main argument to operator new be a parenthesis enclosed abstract declarator (a cast), just like for the sizeof operator, would remove one of the two most prominent causes of nasty syntax ambiguities in C++. -- Piercarlo "Peter" Grandi | ARPA: pcg%uk.ac.aber.cs@nsfnet-relay.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcsun!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk