Overriding placement new correctly

S

SarahT

Hi folks,

I am doing something Very Bad and Wrong (which I'll spare you the
details of) that requires overloading new for some specific classes.
So, for example:

class MyWeirdThingy
{
public:
...
static void* operator new(size_t size)
{
return my_weird_allocator(size);
}
};

This all works fine, there are no problems. However, I do also need to
use placement new for the same class in order to instantiate copies of
it contiguously in memory (as is typically the case with
implementations of std::vector, though I'm actually using my own
collection class).

If I attempt this with code like:

new (ptr) MyWeirdThingy(x)

to copy-construct an instance of the class to a particular address, gcc
wont compile the code because it fails to find an appropriate new
implementation. You can get around the error either by changing the
placement new to:

:: new (ptr) MyWeirdThingy(x)

or by adding a second overload within the class declaration of
MyWeirdThingy for placement new, e.g.:

static void* operator new(size_t size, void* p)
{
return p;
}

which is actually identical to the library version of placement ::new.
It all compiles and seems to work, but the copy construction doesn't
appear to be happening -- I seem to be seeing just default
construction. It is possible (very likely, actually!) that I have a
subtle bug somewhere, but I thought it worth asking whether it is
necessary to do anything beyond the above declaration when implementing
placement new -- since the same new gets called regardless of which
constructor is being invoked, surely you don't need to do anything
weird inside new in this case?

Confirmation that I'm not being stupid here would be appreciated.

Thank you in advance,
Sarah Thompson

PS: My reason for all this craziness is implementing a very unusual
memory model that supports something similar to transaction rollback
for a lattice of 'versions' -- it's part of an experimental model
checker.
 
M

mlimber

SarahT said:
I am doing something Very Bad and Wrong (which I'll spare you the
details of) that requires overloading new for some specific classes.
So, for example:

class MyWeirdThingy
{
public:
...
static void* operator new(size_t size)
{
return my_weird_allocator(size);
}
};

This all works fine, there are no problems. However, I do also need to
use placement new for the same class in order to instantiate copies of
it contiguously in memory (as is typically the case with
implementations of std::vector, though I'm actually using my own
collection class).

Two things:

"Every class-specific overload of void* operator new( /params/) must be
accompanied by a corresponding overload of void operator delete( void*,
/params/ ), where /params/ is a list of extra parameter types (of which
the first is always std::size_t).... The in-place form of operator
new...does not need a corresponding operator delete." --Sutter and
Alexandrescu's _C++ Coding Standards_, Item 45

"If you provide any class-specific new, provide all of the standard
forms (plain, in-place, and no-throw." --_C++ Coding Standards_, Item
46 (The ones you don't care about can just be forwarding functions to
the global versions or, if applicable, using declarations for the base
class's versions.)
If I attempt this with code like:

new (ptr) MyWeirdThingy(x)

to copy-construct an instance of the class to a particular address, gcc
wont compile the code because it fails to find an appropriate new
implementation. You can get around the error either by changing the
placement new to:

:: new (ptr) MyWeirdThingy(x)

or by adding a second overload within the class declaration of
MyWeirdThingy for placement new, e.g.:

static void* operator new(size_t size, void* p)
{
return p;
}

which is actually identical to the library version of placement ::new.

The problem is that defining a class-specific operator new hides all
the other signatures for operator new. If there is a base class
involved that implements new/delete, add a using declaration to the
derived class, or if not, you should just provide a forwarding function
to the global placement new:

static void* operator new(size_t size, void* p)
{
return ::eek:perator new( size, p );
}
It all compiles and seems to work, but the copy construction doesn't
appear to be happening -- I seem to be seeing just default
construction. It is possible (very likely, actually!) that I have a
subtle bug somewhere, but I thought it worth asking whether it is
necessary to do anything beyond the above declaration when implementing
placement new -- since the same new gets called regardless of which
constructor is being invoked, surely you don't need to do anything
weird inside new in this case?

Apart from the above comments, it seems like you are on the right
track. You might want to read section 15.6 of _The C++ Programming
Language_ 3rd ed. by Stroustrup and the two items from _C++CS_
mentioned above. If you need more help, post a minimal but complete
sample that demonstrates the problem (cf.
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8).

Cheers! --M
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top