When I run this code sample in GCC and Clang
struct S
{
int a;
void *operator new(size_t s)
{
std::cout << "new " << s << std::endl;
return ::operator new(s);
}
void operator delete(void *p, size_t s) noexcept
{
std::cout << "delete " << s << std::endl;
::operator delete(p);
}
void operator delete(void *p) noexcept
{
std::cout << "delete " << "none" << std::endl;
::operator delete(p);
}
};
int main()
{
S *p = new S;
delete p;
}
I get the following output from both GCC and Clang
new 4
delete none
which means that the compilers selected the "sizeless" version of operator delete
.
However, if I try something similar with globally replaced operator new
and operator delete
functions
struct S
{
int a;
};
void *operator new(size_t s)
{
std::cout << "new " << s << std::endl;
return std::malloc(s);
}
void operator delete(void *p, size_t s) noexcept
{
std::cout << "delete " << s << std::endl;
std::free(p);
}
void operator delete(void *p) noexcept
{
std::cout << "delete " << "none" << std::endl;
std::free(p);
}
int main()
{
S *p = new S;
delete p;
}
From GCC I get
new 4
delete 4
and from Clang I get
new 4
delete none
I know that "sized" version of in-class operator delete
has been present in C++ since C++98, but looking through C++98 I don't seem to be able to find a definitive answer to the question of what version of operator delete
should be selected in the first example. Is it even specified?
And what about C++14 and its "sized" version of global operator delete
in the second example? Does the language say which version should be selected?
operator delete, operator delete[] Deallocates storage previously allocated by a matching operator new. These deallocation functions are called by delete-expressions and by new-expressions to deallocate memory after destructing (or failing to construct) objects with dynamic storage duration.
When delete is used to deallocate memory for a C++ class object, the object's destructor is called before the object's memory is deallocated (if the object has a destructor). If the operand to the delete operator is a modifiable l-value, its value is undefined after the object is deleted.
The delete operator destroys the object created with new by deallocating the memory associated with the object. The delete operator has a void return type.
Overloading New and Delete operator in c++ The new and delete operators can also be overloaded like other operators in C++. New and Delete operators can be overloaded globally or they can be overloaded for specific classes.
This is CWG issue 255, dating back to the year 2000. To quote its premise:
Paragraph 4 of 15.5 [class.free] speaks of looking up a deallocation function. While it is an error if a placement deallocation function alone is found by this lookup, there seems to be an assumption that a placement deallocation function and a usual deallocation function can both be declared in a given class scope without creating an ambiguity. The normal mechanism by which ambiguity is avoided when functions of the same name are declared in the same scope is overload resolution; however, there is no mention of overload resolution in the description of the lookup. In fact, there appears to be nothing in the current wording that handles this case. That is, the following example appears to be ill-formed, according to the current wording:
struct S { void operator delete(void*); void operator delete(void*, int); }; void f(S* p) { delete p; // ill-formed: ambiguous operator delete }
The status of the issue is currently "drafting", and as of writing this answer it appears still unresolved. There is no wording about overload resolution with regard to the deallocation functions.
Clang and GCC seem to be choosing arbitrarily. I'd argue it would have been better to emit some sort of diagnostic about the operator being ambiguous.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With