Is there a difference between:
operator delete(some_pointer);
and
delete some_pointer;
and if so what is the difference and where one should use one and where the other version of this operator? Thanks.
Is there a difference between:
operator delete(some_pointer);
and
delete some_pointer;
and if so what is the difference and where one should use one and where the other version of this operator? Thanks.
delete some_pointer;
is the "correct" one to use.
operator delete(some_Pointer);
exist mainly as an artifact of the syntax for defining you own delete operator. That is, because you define an plus operator as;
myclass::operator+(myclass b) {....}
you really could write:
myclass c = a.operator+(b);
but no one ever does that. They use:
myclass c = a + b;
Similarly, you could write operator delete(some_Pointer);
, but no one ever does.
operator delete()
simply frees the memory. delete some_pointer
calls some_pointer
's destructor, and then calls operator delete()
.
Ironically, the delete operator and operator delete()
are not the same thing.
delete some_pointer;
calls some_pointer
's destructor, and then calls operator delete()
to free the memory.
You do not normally call operator delete()
directly, because if you do the object's destructor will not be called, and you are likely to end up with memory leaks.
The only time you have to care about operator delete()
is when you want to do your own memory management by overriding operator new()
and operator delete()
.
To top it off, you should also be aware that delete
and delete []
are two different things.
At least in my experience, it's more common to implement operator new
and operator delete
than to actually use (i.e., call) them, at least directly.
Usually, you use operator new
and operator delete
indirectly -- you write a new expression
, like A *a = new A;
. To implement this, the compiler generates code that invokes operator new
to allocate raw memory, then invokes a A::A
to convert that raw memory into an A
object, much as if you'd written:
void *temp = operator new(sizeof A); // allocate raw memory with operator new
A *a = new(temp) A; // convert raw memory to object with placement new
When you're done with the object, you use delete A;
. To implement that, the compiler invokes the dtor for the object, and then frees the memory, roughly like you'd done:
a->~A();
operator delete(a);
There are also operator [] new
and operator [] delete
, which are used when/if you allocate/delete arrays -- but there isn't necessarily any real difference between the normal version and the array version -- they both just allocate a specified amount of raw memory (though you might guess that the array versions will allocate relatively large amounts of memory, and do some optimization on that basis).
In any case, if you want to optimize how memory is allocated for objects of a particular class you overload these to do it. There are a fair number of existing implementations that you can drop-in and use, especially for situations where you expect to allocate a large number of tiny objects so you need to minimize the overhead associated with each allocation (e.g., HeapLayers, Loki's small block allocator).
One interesting little tidbit: operator new
, operator [] new
, operator delete
and operator [] deleteare always
staticclass members, even if you don't explicitly include
static` in their declaration/definition.
There are also global versions of all four (::operator new
, ::operator [] new
, ::operator delete
and ::operator [] delete
). These mark the "border" between the "internal" C++ memory management, and the outside world. Typically they allocate relatively large chunks of memory from the operating system, and then return smaller pieces to the rest of the program upon request. If you want to (try to) optimize memory management for your entire program, you typically do it by overloading (or, really, replacing) these. Again, the typical reason would be if you expect to allocate a lot of small objects (but not in just a few classes). One example of this is the Boost Pool library.
Direct use of any of the above is generally restricted to situations where you need a block of raw memory, not objects. One example would be implementing your own container classes. For example, std::vector
normally uses ::operator new
(via an Allocator object) to allocate memory in which to store objects. Since it needs to be able to allocate storage, but only later (or perhaps never) create objects in that storage, it can't just use something like data = new T[size];
-- it has to allocate raw memory, then use placement new to create objects in the memory as you add them to the collection (e.g., when you push_back
an object). The same is true with std::deque
. If you wanted (for example) to implement your own circular buffer "from the ground up", handling all the memory management directly instead of using something like vector
for storage, you'd probably need/want to do the same.