The new operator in C++ |
Written by Eli Bendersky | ||||
Tuesday, 29 March 2011 | ||||
Page 3 of 3
Deleting an allocated objectOne 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; 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:
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, C++ dictates that to free such an object, a matching delete with the same arguments is looked for. inline void operator delete 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. ConclusionThis 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
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 ) |