Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!microsoft!jimad From: jimad@microsoft.UUCP (Jim ADCOCK) Newsgroups: comp.std.c++ Subject: Re: Asymmetry: "new (placement) T" vs. "Tptr->~T" Keywords: placement new delete constructor destructor template Message-ID: <57159@microsoft.UUCP> Date: 4 Sep 90 18:38:34 GMT References: <620@dlogics.COM> Reply-To: jimad@microsoft.UUCP (Jim ADCOCK) Organization: Microsoft Corp., Redmond WA Lines: 70 In article <620@dlogics.COM| jmd@dlogics.COM (Jens M. Dill) writes: |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 () ; The asymmetry exists, should the language attempt to hide it? New creates an object where one did not previously exist. How can you use object syntax on something that isn't [yet] an object? Conversely, shouldn't destruction syntax reflect that destruction is being applied to something that *is* an object? |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). I disagree that the intended purpose of new and delete is to allocate/ deallocate memory. I claim instead the the intended purpose of new and delete is the dynamic creation / destruction of objects. "Placement" syntax then makes perfect sense -- the parameters allow one to specify variations in where one dynamically creates an object. The fact that heap allocations and deallocations may need to be performed to allow objects to be dynamically created and destroyed is the side effect, not the primary effect of new and delete.. |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. It is already legal to explicitly call [do-nothing] destructors on built-in types [E&S pg 280] Other classes should explicitly declare destructors, if so needed. If a given protocol, such as might be required by a stack template, requires a destructor, then put a destructor in the protocol definition. Derived classes then automatically get a destructor. Conversely, a class writer may explicitly choose to not have a destructor. Such a design decision might be reasonable if writing a class whose objects are intended never to be destroyed. Allowing a compiler to generate destructors for classes from the void prevents such a design choice. I counter-propose: no change.