The new operator in C++
Written by Eli Bendersky   
Tuesday, 29 March 2011
Article Index
The new operator in C++
Allocation
Deleting an allocated object

Deleting an allocated object

One of the maxims of C++ is that objects allocated with new should be deallocated with delete. Is this also true for objects allocated with placement new? Not quite:

int main(int argc, const char* argv[])
{
 char mem[sizeof(int)];
 int* iptr2 = new (mem) int;

delete iptr2;
// Whoops, segmentation fault! return 0; }

To understand why delete iptr2 in the snippet causes a segmentation fault (or some other kind of memory violation, depending on the operating system), let’s recall the description of what delete iptr2 actually does:

  1. First, the destructor of the object that’s being deleted is called.
  2. Then, the memory occupied by the object is returned to the OS, represented by the global operator delete function.

There’s no problem with the first step for an object allocated with placement new, but the second one looks suspicious. Attempting to free memory that was not actually allocated by the memory allocator is definitely a bad thing, but it’s exactly what the code sample above does. iptr2 points to some location on the stack which was not allocated with global operator new. And yet, delete ipt2 will try to deallocate it with global operator delete. Segmentation fault indeed.

So what do we do? How do we properly delete iptr2? Well, we surely can’t expect the compiler to figure out how to deallocate the memory – after all, we just pass a pointer to placement new – that pointer could’ve been taken from the stack, from some memory pool or somewhere else. So deallocation has to be manual.

As a matter of fact, the placement new used above is just a special case of a generalized placement new syntax allowed by C++ for specifying extra arguments in new. It’s defined in the standard header <new> as follows:

inline void* operator new(std::size_t, 
void* __p) throw() { return __p; }

C++ dictates that to free such an object, a matching delete with the same arguments is looked for.
This one is also defined in <new>:

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

Indeed, the C++ runtime just doesn’t know how to deallocate such an object, so the delete is a no-op.

What about destruction? For an int, no destruction is really needed, but suppose the code would be:

char mem[sizeof(Foo)];
Foo* fooptr = new (mem) Foo;

For some non-trivial class Foo, what do we do to destruct fooptr once we don’t need it anymore?

We have to call its destructor:

fooptr->~Foo();

Yes, calling the destructor explicitly is actually valid in C++, and this is probably one of the only cases where it makes sense to do it - in fact, the standard vector container uses it to destruct objects it holds.

Conclusion

This is a complex topic, and the article only served as an introduction, giving a "quick taste" of the various methods C++ provides for memory allocation. There are many interesting gotchas and programming tricks once you start going down some specific road (for example, implementing a pool allocator). These are best presented in their own context and not as part of a general introductory article. If you want to go deeper, check the Resources section below.

Resources

  • C++ FAQ Lite, especially items 11.14 and 16.9
  • "The C++ Programming Language, 3rd edition" by Bjarne Stroustrup – 10.4.11
  • "Effective C++, 3rd edition" by Scott Myers – item 52
  • "Modern C++ Design" by Andrei Alexandrescu – chapter 4
  • Several StackOverflow discussions. Start with this one and browse as long as your patience lasts.

personalheader

 

This article was originally published as The many faces of operator new in C++ on Eli Bendersky's website and has been used here with kind permission of the author.



Last Updated ( Tuesday, 29 March 2011 )