Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!dlogics!jmd From: jmd@dlogics.COM (Jens M. Dill) Newsgroups: comp.std.c++ Subject: Asymmetry: "new (placement) T" vs. "Tptr->~T" Keywords: placement new delete constructor destructor template Message-ID: <620@dlogics.COM> Date: 29 Aug 90 20:37:44 GMT Organization: Datalogics Inc., Chicago Lines: 61 Is anyone else bothered by the inherent asymmetry in the application of constructors and destructors to an object that is to reside in a known memory location? To take a known area of memory and intitialize it as an object of type T, one is supposed to use the "placement" form of the "new" operator, which implicitly invokes any necessary constructor: T* Tptr = new (KnownArea) T ; To undo this, one is supposed to apply the destructor ~T explicitly: Tptr->~T () ; This is all very well if one knows whether or not T is a class with a destructor, but consider the case where T is a type argument to a template (or to a macro that emulates the template facility). In this case, one cannot know if T is a type with constructors or destructors, since that information is unavailable until T is bound in a template-class definition. This causes no problems with the constructor invocation, since the constructor is invoked implicitly by operator new, which can be applied to objects of any type, whether or not they have constructors. The problem comes with ensuring that the destructor is properly invoked. Here, one must invoke the destructor explicitly, since operator delete may not be applied to memory not allocated by operator new. But one may not invoke the destructor explictly if no destructor id defined. And one has no way of telling, for a template type- argument T, whether or not T has a destructor. Possible fixes: 1. Define a version of the delete operator that accepts an indicator telling it that the memory is not to be returned to the heap, as it was allocated by some other mechanism. This is the most symmetric and general solution, but I can think of no good syntax for it, and it perpetuates a problem introduced by the "new" placement syntax: namely, that "new" and "delete" are being invoked for their side effects only (constructor/destructor invocation) rather than for their intended purpose (heap allocation/ deallocation). 2. Make it legal to explicitly invoke a destructor for any type T, whether or not it has one. Invocations of the form "Tptr->~T" where T is a primitive type or the name of a class without a destructor would do nothing. This solves the problem, even though it retains the asymmetry. 3. Other variants, etc. I do not see an obious best choice here. For those who are interested, the problem arose when defining a stack template that allocates space in multi-element frames. Rather than initializing all elements of the stack frame at the time the frame was allocated (which would be relatively easy), I wanted to initialize each element as it receieved a new value (via PUSH) and invoke the destructor for the corresponding POP. There is a workaround: declare yet another container class that holds just one stack element and defines only the new and delete operators to have the PUSH and POP semantics. Perhaps that workaround is purer C++, even though it introduces a gratuitous class definition. *=====* TIME CANNOT BE WASTED *=====* -- Jens M. Dill \ But it can be used for purposes / jmd@dlogics.com \ other than what was intended. / *=============================*