Re: explicit call of constructor and destructor
* Abhishek Padmanabh:
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>)?
"user defined placement form" is AFAIK not a term employed by the
standard, nor is it a commonly used term. But assuming you mean it as a
description: a "new" expression for single object accepts two lists of
arguments,
new (arglist1) T(arglist2)
arglist1 is passed to the allocation function, so by definining an
allocation function (which unfortunately is named "operator new") you
enable a particular signature for this argument list.
arglist2 is passed to a T constructor, so by definining a constructor
you enable a particular signature for this argument list.
There's not really more to it.
operator new/operator delete overloads should match the signature of
their global forms provided by the compiler.
No.
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.
Huh?
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?
It seems you are assuming a distinction that does not exist.
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 current standard's ?5.3.4/20 does not have the above example, or any
example. However, this example is in ?5.3.4/20 of the draft for C++0x.
That paragraph correspond to ?5.3.4/19 in the current standard.
The rule concerning the ill-formed'ness of the above example was added
in the draft.
It's a special case that evidently wasn't considered in the 98 standard.
The standard also says (in 18.5.1.3 - Placement forms)
In the current standard this is ?18.4.1.3.
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();
No, it's specific to the two forms of operator new and two forms of
operator delete specified there, in the global namespace.
and if I had a different argument list for this - would that be
allowed?
Subject to the constraints on the signature of an "operator new", yes.
However, best advice is to stay away from low level features (and these
are very low level features) of the language, unless you are experienced
and really really need them and understand the implications of using them.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?