Re: placement new and delete
On Jun 19, 3:14 am, LuB <lutherba...@yahoo.com> wrote:
On Jun 17, 3:20 pm, James Kanze <james.ka...@gmail.com> wrote:
On Jun 17, 10:08 pm, LuB <lutherba...@yahoo.com> wrote:
I am constantly creating and destroying a singular object used within
a class I wrote.
To save a bit of time, I am considering using 'placement new'. I guess
we could also debate this decision - but for the sake of this post ...
My first question would be: how will it save time?
It doesn't allocate memory. It essentially just returns a pointer.
The memory has to be allocated somehow, in every case. You
can't construct an object without having the memory for it.
I had more or less assumed that the memory would be declared as
as local variable. In which case, the comparison isn't with
non-placement delete, but with just declaring a local instance
of the object.
I'm searching for an answer that assumes said decision.
If I allocate memory in the class declaration:
and use 'placement new' inside of of an instance' method:
pObjectX = new (buffer) ObjectX;
You likely get undefined behavior. You have to do something to
ensure that buffer is correctly aligned.
Not sure I follow
If you've declared buffer as a local (or a static) object:
char buffer[ sizeof( ObjectX ) ] ;
you're not at all guaranteed that it will be correctly aligned
for an ObjectX; on my system, if very often won't be.
but then, maybe my example wasn't clear.
struct ObjectX { int x; int y; };
struct UserAnObject
{
char buffer[sizeof(ObjectX)];
void onMouseDown()
{
pObjectX = new (buffer) ObjectX;
// do something here
}
void onCaptureChanged()
{
// finish doing something here
pObjectX->~ObjectX();
operator delete (pObjectX_, buffer);
}
ObjectX* pOBjectX;
};
And where is UserAnObject declared? In this case (a bit
special), you're garanteed that the buffer has the same address
as the whole object (but only because UserAnObject is a
POD---add a constructor, for example, and you loose the
guarantee), but this doesn't necessarily mean that it is
sufficiently aligned for an ObjectX. Again, on my system, when
compiling in 32 bit mode, the compiler will ensure that all
UserAnObject are aligned on an address multiple of 4, because
this is necessary for the pointer it contains, but if ObjectX
contains a double, it requires an alignment on a multiple of 8.
If UserAnObject in fact contains virtual functions, the compiler
will insert the vptr before "char buffer[]", almost guaranteeing
that it will NOT be correctly aligned for a double if
UserAnObject is dynamically allocated.
Also: you don't really have to call operator delete here. The
standard guarantees that it is a no-op, but in general, if the
operator new called by the new expression doesn't allocate any
resources, you don't need to call operator delete.
then, when it comes time to clean up, I understand that I must
explicitly invoke the destructor .... but its not clear to me if I
need to use placement delete at all?
pObjectX->~ObjectX();
operator delete (pObjectX_, buffer); // ?????? is this or some
version of this required? or more-safe?
I'm not sure what you're even trying to do here.
See above for clarification.
OK. It's not necessary, and it's not usual to see it (although
the standard guarantees that it will work).
[...]
you should provide a corresponding placement delete.
If in a new expression which uses your placement new function,
the constructor of the object exits with an exception, the
compiler will call your placement delete.
Not sure how it will call 'my placement delete' unless you're
referring to a class member. My example does not define a 'placement
delete'. I am wondering if I should invoke the global placement
delete ... (hope that makes sense).
For the standard placement new and delete, there's really never
any reason to call placement delete. For a user defined one,
however...
Consider something like:
union BlockHeader { Allocator* alloc, double forAlignment } ;
void*
operator new( size_t n, Allocator* pAlloc )
{
BlockHeader* p =
static_cast< BlockHeader* >(
pAlloc->alloc( n + sizeof( BlockHeader ) ) ;
if ( p == NULL ) {
throw std::bad_alloc() ;
}
p->alloc = pAlloc ;
return p + 1 ;
}
void*
operator new( size_t n )
{
BlockHeader* p =
static_cast< BlockHeader* >( malloc( n +
sizeof( BlockHeader ) ) ;
if ( p == NULL ) {
throw std::bad_alloc() ;
}
p->alloc = NULL ;
return p + 1 ;
}
void
operator delete( void* userPtr )
{
BlockHeader* p
= static_cast< BlockHeader* >( userPtr ) - 1 ;
if ( p->alloc == NULL ) {
free( p ) ;
} else {
p->alloc->free( p ) ;
}
}
According to the rules, if you do something like:
MyType* p = new ( someAllocator ) MyType ;
and the constructor of MyType exits via an exception, no
operator delete function will be called. If you have a
corresponding placement delete, however, it will be called.
Since in this case, you are actually allocating memory in your
placement new, you should provide a placement delete, so that it
will be called.
--
James Kanze (GABI Software, from CAI) 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