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++
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,
then actually the following (pseudo-)code is executed:
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:
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
really only calls the overloaded operator delete, without destructing the object before. So I had to expand my workaround to look like this
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.
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 Comments
Add Comment