Piko3D

Tutorial: Placement New Operator

Updates
7-01-2011 14:17
Changed and extended the information on possible heap corruptions

Introduction:

This tutorial can be helpfull for people trying to write their own array, or thinking about implementing a memory pool, and is meant for the advanced programmer. Piko3D uses it’s own array implementation which turned out to be about 25% faster than the std::vector (in optimized release, 500% faster in debug) and easier to use.

When writing your own array or memory pool, you might come to a point where you need to new an object into your own memory block. This in order to have C++ call the proper constructor or copy constructor and initialize your memory properly.

This is where overloading the new operator, or placement new, comes in handy.

The Code

The new() operator can be overloaded. In fact: Our friend the std::vector uses a placement new() operator to copy construct objects in a pre-allocated buffer.  You can use it by including <new> And it works like this:


1
2
3
4
5
6
7
8
//the missing variable after size_t means we don't actually use this parameter
//We only use buffer
void* operator new (size_t, void* buffer) {
    return buffer;
}

void operator delete(void*, void*) {
}

Yes.. that’s it… It doesn’t do anything. See here’s how operator new() works: It calls the operator and passes a size_t to specify how much memory is needed to allocate the object. Now all it asks is that you return a void* to a block of memory that’s big enough!

What we do here, is overload the new operator, so that it takes one more parameter: The void* to the buffer where we want to place our object. We can return it, so that C++ will place our object in our buffer!

Please note that we’ve also overloaded a delete operator. This delete operator is here, so the compiler knows what to call when our placement new fails. It does nothing, since the placement new doesn’t actually allocate any memory of its own.. But if you don’t specify this operator delete, you will get a compiler warning.

You use the placement new like this:


1
2
3
4
//We allocate enough space for 10 instances of Foo
Foo buffer* = (Foo*)malloc(sizeof(Foo) * 10);
//We construct a Foo object in our memory block.
new (&buffer[0])  Foo();

Notice that we pass the adress of the buffer’s first object, object[0], as the adress where we want our Foo to be placed! C++ will then use the space pointed to by the returned pointer to call the object constructor on.

IMPORTANT: BE CAREFUL WITH DELETES!!

You do NOT want to call delete on placement newed objects, unless the memory allocated is only used by a single constructed object, AND that object is constructed at the start of the block! In this case the ENTIRE block will be deleted. Not just the object. Calling delete in any other case will result in HEAP CORRUPTION! Since a block descriptor with extra information about the size of the block is stored when allocating a block of memory, deleting an object in the middle of the memory block will cause delete to look for the block descriptor in the wrong place! This will cause a memory block of undetermined size to be freed o_O…. MORE HEAP CORRUPTION!!

If you want to destruct an object that you have created with your placement new (unless it’s the only object in the block and it’s at the start of the block) you will HAVE TO call the destructor explicitly. This is about the only case where you’ll ever have to call the destructor explicitly… but here’s how that looks:


1
2
3
4
5
class Foo {};

void destroyElt(Foo& elt1) {
    elt1.Foo::~Foo();
}

Wrapping up…

To be complete, std also defines placement news for arrays (new []) . They work in exactly the same fashion. Using the <new> header is nice because it defines all the standard placement news and calling conventions for them. Plus they also implement the much needed matching delete operatators.

Ofcourse you can also define your own placement new. You could change the void* to whatever you would want to use in the new operator to allocate your memory. However when implementing a memory pool for instance, it may be that you’d also have to have an overwritten delete operator. The ones provided only work when new fails. You cannot overload the global delete! If you want to overload the delete for a class, you’d have to overload it as a class member.

If you go and overwrite the new and delete in a class, this overwrites the use of your placement new. If you still want to be able to use this object with placement news, you’d have to define your class new and a separate placement new for that class, in order for it to work in, let’s say, your array, or an std::vector for that matter.

Hope this helped! If you still have questions, remarks, tips, or want to know more details, just drop me a line, or leave a comment.

4 Comments »

Comment by huahsin68 — May 30, 2010 @ 6:39 am

Hi,

According to C++ practice, it is not good to explicitly call destructor directly. Do you have alternate solution to remove the object from the heap? BTW, do you have a sample code to show that the deletion of object is working?

THanks @!

Comment by Wracky — May 30, 2010 @ 11:34 am

Hi and thanks for your comment!
As far as I am aware, there is no other way to solve this problem (if you find one, let me know ;-)) Implementations that use the placement new operator, like the STL container classes (std::vector<> for example) use this exact method.

It’s good to know what’s good coding practice, what’s not, and why it isn’t… but part of the beauty of C++ is, that it will LET YOU if you REQUIRE such actions.

Calling the default destructor directly does not remove the object from the heap. It just makes sure the object’s destructor code is run. The actual deallocation of heap memory is up to you. In this example I’ve allocated the memory block with a simple “malloc” which means I can only deallocate it by calling “free” on the complete block. Other actions will cause heap-corruption.

As I said in the beginning, it’s a more advanced topic… there’s a lot that can go wrong here 🙂

I’ve corrected some character problems caused by wordpress. The sample code should compile now, and you can use it to make your own Foo class and see the destructor get called.

Good luck! 🙂

Comment by SB — March 14, 2014 @ 12:42 am

I know this is old but I just happened across it, and I wanted to respond to the “good practice” comment in case anyone reads it and isn’t sure what to think.

Ordinarily huahsin would be correct, but not in this case. You have to stop thinking of this as ordinary user code and think of it more as being system code. You are taking over the mechanical duties of memory allocation and deallocation, and so procedures like the explicit call of dtors is necessary. There’s nothing wrong with this; you’re taking over for the code that normally does this kind of thing, and so that’s just the way it is.

Comment by Wracky — March 17, 2014 @ 3:01 pm

Hi SB,

Exactly. Thank you for your addition

Regards,
Wracky

RSS feed for comments on this post. TrackBack URL

Leave a comment

 

Creative Commons License
This work by piko3d.net is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Netherlands License
Powered by WordPress