Re: explicit call of constructor and destructor
On Dec 4, 8:30 pm, James Kanze <james.ka...@gmail.com> wrote:
On Dec 4, 4:47 am, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
[...]
This is crucial, because the
constructor might throw an exception. The placement new expression sets
up an exception handler first of all, which has responsibility for
deallocation, before it calls the constructor for you -- the explicit
syntactical constructor call in the expression is, at the level of
execution, a wrapped call.
Sorry, this is new to me. How could the handler be set up by
the placement new call?
There are four different ways the compiler can generate code for
a new expression, depending on whether there is a corresponding
(placement) delete, and whether the operator new function is
declared not to throw or not. Basically (for p = new T):
corresponding delete, operator new() may throw:
T* tmp = operator new( sizeof(T) /* , any placement params.
*/ ) ;
try {
T::constructor( tmp ) ;
} catch ( ... ) {
operator delete( tmp /* , any placement params. */ ) ;
throw ;
}
corresponding delete, operator new declared with throw()
T* tmp = operator new( sizeof(T) /* , any placement params.
*/ ) ;
if ( tmp != NULL ) {
try {
T::constructor( tmp ) ;
} catch ( ... ) {
operator delete( tmp /* , any placement params. */ ) ;
throw ;
}
}
no corresponding delete, operator new() may throw:
T* tmp = operator new( sizeof(T) /* , any placement params.
*/ ) ;
T::constructor( tmp ) ;
no corresponding delete, operator new declared with throw()
T* tmp = operator new( sizeof(T) /* , any placement params.
*/ ) ;
if ( tmp != NULL ) {
T::constructor( tmp ) ;
}
As you can see, if there is a corresponding operator delete, the
compiler must call it if the constructor terminates with an
exception.
Note that except for the case of a placement new expression with
no corresponding delete or a local static variable, the compiler
always frees the memory allocated for the variable being
constructed. Except in new expressions, however, this all
happens behind the scenes, where you cannot get at it to
instrument. (While I've shown this as try blocks in the above,
it's more likely that the compiler uses the same mechanism it
uses to call destructors of local variables in practice.)
Ok, thanks for that. So then, how is an operator new overload (which
can be called an allocation function, right?) different from a user
defined placement new form (not using the one for in place
construction as available in <new>)?
operator new/operator delete overloads should match the signature of
their global forms provided by the compiler. And then when the objects
of the class, for which these are overloaded, are created using new
expression, use the operator new overload for allocation and the
corresponding operator delete for deallocation.
If placement allocation function and placement deallocation functions
also manage allocation and deallocation then what is different between
these and the above overloads? Just that if the signature if a direct
match with operator new/operator delete, they are overloads else they
are placement allocation functions?
Also, referring to the example as in 5.3.4 (20) as below:
struct S {
// Placement allocation function:
static void* operator new(std::size_t, std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function
matches
// placement allocation function
The standard also says (in 18.5.1.3 - Placement forms) that the
placement form function is reserved and a C++ program may not define
them that would displace these? Is that specific to the form as below:
void* operator new(std::size_t size , void* ptr ) throw();
and if I had a different argument list for this - would that be
allowed?