`оператор delete` с параметром размера и без параметра размера: какой из них выбирается, когда оба доступны? - PullRequest
5 голосов
/ 30 мая 2019

Когда я запускаю этот пример кода в GCC и 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;
}

Я получаю следующий вывод от GCC и Clang

new 4
delete none

, что означает, что компиляторы выбрали «безразмерную» версию operator delete.

Однако, если я попробую что-то похожее с глобально замененными operator new и operator delete функциями

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;
}

Из GCC я получаю

new 4
delete 4

и из Clang я получаю

new 4
delete none

Я знаю, что "размерная" версия класса operator delete присутствует в C ++ начиная с C ++ 98, но, просматривая C ++ 98, я не могу найти окончательного ответа на Вопрос о том, какую версию operator delete следует выбрать в первом примере. Это вообще указано?

А как насчет C ++ 14 и его "размерной" версии global operator delete во втором примере? Язык говорит, какую версию следует выбрать?

1 Ответ

8 голосов
/ 30 мая 2019

Это выпуск CWG 255 , датируемый 2000 годом. Процитируем его предпосылку:

В пункте 4 из 15,5 [class.free] говорится о поискефункция освобождения.Несмотря на то, что при поиске обнаруживается только одна функция освобождения места размещения, существует предположение, что функция освобождения места размещения и обычная функция освобождения могут быть объявлены в заданной области видимости класса без создания неоднозначности.Обычный механизм, с помощью которого можно избежать неоднозначности, когда функции с одинаковыми именами объявляются в одной и той же области видимости, - это разрешение перегрузки;однако в описании поиска нет упоминания о разрешении перегрузки.На самом деле, в нынешней редакции, похоже, нет ничего, что могло бы справиться с этим делом.Таким образом, следующий пример представляется некорректным в соответствии с текущей формулировкой:

struct S {
    void operator delete(void*);
    void operator delete(void*, int);
};
void f(S* p) {
    delete p;    // ill-formed: ambiguous operator delete
}

Статус вопроса в настоящее время "находится на стадии разработки", и на момент написания этого ответа он появляетсявсе еще не решен.Нет никакой формулировки о разрешении перегрузки в отношении функций освобождения.

Clang и GCC, кажется, выбирают произвольно.Я бы сказал, что было бы лучше выдать какую-то диагностику о неоднозначности оператора.

...