operator delete != delete operator

Posted by Kaya Kupferschmidt • Monday, January 23. 2006 • Category: C++
Today I had an important lesson about a subtle detail that hides behind overloading the new and delete operator in C++. Actually in most cases, you do not need to overload these operators, but the possibility to do so comes in handy if you want to work with your own allocation schemes. So the following code is just legal in C++

class Myclass {
public:
Myclass();
~Myclass();
void* operator new(size_t size);
void operator delete(void* );
};


Now this skeleton allows you to use a custom memory pool for objects from Myclass. But this is not all. When you now create and delete an object of type "Myclass" with the following code,

Myclass* obj = new Myclass();
delete obj;

then actually the following (pseudo-)code is executed:

void* mem = Myclass::operator new(sizeof(Myclass));
mem->Myclass();
Myclass* obj = static_cast(mem);

obj->~Myclass();
Myclass::operator delete(obj);

So far so nice, but you can even do some more advanced stuff by passing some additional parameters to the new operator. This can be useful if you want to pass an additional object to new that encapsulates a specific memory pool to use for the actual allocation. The code would look like this:

class Allocator {
...
};

class Myclass {
public:
Myclass();
~Myclass();

void* operator new(size_t size, Allocator* );
void operator delete(void* ,Allocator* );
};


Allocator alloc;
Myclass* obj = new(&alloc) Myclass();
delete(&alloc) obj;

At least, it would be nice, if the code above was accepted by the compiler. But Visual Studio gripes about the last line, the delete(&alloc) obj. So I tried to work around by typing operator delete(obj, &alloc) instead. This code was accepted, but just today while tracking down some memory leaks, I found out that this code actually does exactly what it stands for - and nothing more. Especially this line of code does not call the destructor. I googled a bit around and found a short FAQ article about Delete operator versus operator delete, which explained the situation a bit. The compiler was right. Simply calling

operator delete(obj);

really only calls the overloaded operator delete, without destructing the object before. So I had to expand my workaround to look like this

Allocator alloc;
Myclass* obj = new(&alloc) Myclass();
obj->~Myclass();
delete(&alloc) obj;

This refinment solved a lot of memory leaks caused by my formerly wrong List, Set and Map implementation, which all use allocators to reduce system calls for memory allocations (and yes, if you have a lot of small objects, this can improve performance by a magnitude).

The moral of this article is just mentioned in the article: calling operator delete is not equivalent to calling the delete operator.

0 Trackbacks

  1. No Trackbacks

0 Comments

Display comments as (Linear | Threaded)
  1. No comments

Add Comment


Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA