Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`operator delete` with size parameter and without size parameter: which one is chosen when both are available?

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?

like image 965
AnT Avatar asked May 29 '19 21:05

AnT


People also ask

How does operator delete work?

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.

How delete operator works in c++?

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.

What kind of expression is the new Delete operator?

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.

Can we overload delete operator in C++?

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.


1 Answers

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.

like image 185
StoryTeller - Unslander Monica Avatar answered Sep 28 '22 07:09

StoryTeller - Unslander Monica