Re: explicit call of constructor and destructor
On Dec 5, 6:03 am, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
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:
[...]
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>)?
Attention. We're dealing with two different things here. You
can overload the global operator new function, by providing one
with a different signature, and you can replace the standard
operator new function with one of your own.
In the second case, your function must have exactly the same
signature and the same semantics as the original, including
throwing std::bad_alloc (or a class derived from it) in case of
insufficient memory. And there *is* a corresponding operator
delete function for this, so any new expression using it will
require the compiler to generate code ensuring that the operator
delete function is called if the constructor exits via an
exception.
In the first case, of course, it's up to you. You can either
report failure by means of bad_alloc, or you can declare the
function throw(), and return a null pointer. You can provide a
corresponding placement delete, which will be called if the
constructor exits via an exception, or not (in which case
nothing will be called).
operator new/operator delete overloads should match the
signature of their global forms provided by the compiler.
If the signatures match, then it's not an overload, it's a
replacement.
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?
They use different algorithms?
The most frequent case I've seen is something like:
void* operator new( size_t n, MemoryPool& ) ;
void operator delete( void* p, MemoryPool& ) ;
Invoked by something like:
MemoryPool pool1 ;
T* p = new ( pool1 ) T ;
In this case, you probably need the placement delete, since if
the constructor fails, you want to delete the memory. (Or maybe
the pools are garbage collected in some way, and you don't need
it.)
Just that if the signature if a direct match with operator
new/operator delete,
If the signature is a direct match, they are replacements, not
overloads.
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
This is a special case. The problem with member operator delete
is that the non-placement form can have one of two different
signatures. Which leads to an ambiguity if the placement form
of new takes a size_t as it's additional argument: is the
operator delete, above, a placement form (which should be called
if the constructor in a corresponding placement new throws), or
is it the standard form (in which case, it will only be called
if non-placement new is used).
On the whole, my comments didn't take member overloads of
operator new into consideration, but except for the fact that
the non-placement delete can have one of two different
signatures, the rules are pretty much the same. Of course, the
name lookup rules means that a placement operator new in a class
will hide the global non-placement operator, so objects of that
type can only be created by placement new.
More generally, overloading operator new and operator delete can
be tricky; it's not something for beginners.
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?
Exactly. You are not allowed to replace this form of placement
new, since much of the standard library code probably depends on
it having exactly the semantics provided for by the standard
library.
Note that at a language level, there's nothing special about
this level. As far as the compiler is concerned, the new
expression behaves as always: it calls an allocator function to
acquire the memory, then the constructor of the object. Because
this particular placement new is declared nothrow, the compiler
will also generate code to check that the returned pointer is
not null before calling the constructor. Because the library
also declares a corresponding placement delete, the compiler
will also generate code to ensure that it is called if the
constructor exits via an exception. (I've often wondered about
this; the semantics of the corresponding placement delete are to
do nothing, so I don't see the reason behind having it, and
getting it called. Perhaps just to prevent user code from
accidentally declaring it.)
And of course, by using this "allocator", the language itself
never violates the rule that a constructor cannot be invoked
without memory allocation.
The more I think about it, the more I think that constructors
really are somewhat special. All other member functions,
including the destructor, are either static or non-static. If
they're static, there's no object, and not this pointer. If
they're non-static, they are always called on a specific object,
whose address becomes the this pointer. The constructor is
special in that it not called on an object---before the
constructor is called, the object doesn't exist---but that it
has a this pointer. So it's really a third type of member
function, not really static (since it has a this pointer), but
not really non-static either (since you don't need an object to
call it). The standard could have provided a special syntax,
say p->TypeName() (where p would have type void*, or be
convertible to a void*), to call the constructor, without any
allocation. But this would be a special syntax: the "placement
new" trick works just as well, and the operation isn't frequent
enough to warant a special syntax.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34