Question:
Is there a difference in the declaration of operator delete(void*)
and operator delete(void*, size_t)
for a class? Is the second parameter really needed? And if so, why?
Answer:
The presence of the second optional parameter of type size_t
in the operator delete
function has been going on since the days of the "classic" C ++, i.e. C++98, where such a parameter could be used in operator delete
overloaded specifically for individual . That is, inside a particular class, you can choose to declare
operator delete(void *p);
// или
operator delete(void *p, size_t s);
In a situation where the class being deleted provides its own overloaded operator delete
with a second parameter of type size_t
, the compiler must pass the correct size of the memory block to be deleted to such an operator, i.e. the same size that was passed to operator new
when this block was allocated.
For the global operator delete
, this was not provided.
This possibility is provided in the language due to the fact that the overloaded operator new
and operator delete
of the base class can be used to allocate / deallocate memory for objects of derived classes.
struct Base
{
void *operator new(size_t s)
{
std::cout << "new " << s << std::endl;
return ::operator new(s);
}
void operator delete(void *p, size_t s)
{
std::cout << "delete " << s << std::endl;
::operator delete(p);
}
};
struct Derived : Base
{
char buffer[1024];
};
int main()
{
Base *pb = new Base;
delete pb;
Derived *pd = new Derived;
delete pd;
}
By parsing the values passed to operator new
and operator delete
, these operators can determine which of the possible sizes is allocated or deallocated and redirect calls accordingly.
For the global functions ::operator new
and ::operator delete
there was no such possibility in C++98; only the replacement was provided globally
operator delete(void *p);
However, since C++14, this possibility has been provided for global functions too. This was done to improve support for allocators that do not store the block size in the block itself (or somewhere nearby), i.e. for allocators for which it is difficult to determine the block size from the pointer. For example, for pools of one-dimensional objects. Also, this feature can be useful for optimizing memory allocation / deallocation in the possibility of extended memory allocations that appeared in C ++ 14, when two or more neighboring new expressions are managed by one operator new
call with a total size (and, accordingly, symmetrical processing of delete expressions ).
That is, if for some reason you want to receive the same size in ::operator delete
as was passed in the corresponding call to ::operator new
, then declare your ::operator delete
with a second parameter of type size_t
. If you are not interested in this size, then declare it without such a parameter.
The situation with the presence of two variants of operator delete
at once seems to have been in limbo for a long time and isa defect in the standard . Most likely, the case will end up with the fact that providing two options at once will lead to an ambiguity error.