Как должно вести себя переопределение удаления в C++?

Проблема, с которой я сталкиваюсь, заключается в том, что, насколько мне известно, оператор удаления должен быть статической функцией, но иногда компилятор (VC++), кажется, рассматривает ее как динамическую.

Дано:

class Base
{
public:
  void* operator new(size_t size) { /* allocate from custom heap */ }
  void operator delete(void *p) { customFree(p, sizeof(Base)); }

  Base() {}
  virtual ~Base() {}
};

class Derived: public Base
{
public:
  void* operator new(size_t size) { /* allocate from custom heap */ }
  void operator delete(void *p) { customFree(p, sizeof(Derived)); }

  Derived() {}
  virtual ~Derived() {}
}

Что я вижу, так это то, что удаление базового указателя приведет к вызову Derived::opeator delete.

Base *p = new Derived();
delete p; //calls Derived::operator delete

Если я не определю ЛЮБОЙ деструкторы, тогда я получу то, что ожидал: вызывается удаление Base :: operator. Похоже, это происходит потому, что компилятор вставляет функцию, называемую «скалярное удаление деструктор», в vtable, когда определено деструктор. Затем эта функция вызовет Derived::delete.

Итак, у меня есть вопросы: 1) Это стандартное поведение? 2) Когда мне следует использовать

void operator delete( void *, size_t );

против.

void operator delete( void * );

если это стандартное поведение?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
0
15 389
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это определенно стандартное поведение. Если использовался оператор new производного класса, также будет использоваться оператор delete это (также обратите внимание, что, хотя вы явно не указываете компилятору, что эти функции статичны, они неявно объявлены в находятся). Возможен неприятный случай, когда у вас есть оператор new в производном классе, но соответствующий оператор delete находится в базовом классе. Я думаю, что это правильно, но я бы этого избегал. Использование базового оператора delete при определении собственного нового оператора new в производном классе неизбежно вызовет проблемы.

If I don't define ANY destructors then I get what I expected to happen:

Вы получите неопределенное поведение :) Все может случиться, в том числе и то, чего вы ожидаете (ошибочно). Для удаления с помощью базового указателя, указывающего на объект другого типа, требуется виртуальный деструктор. Неявно объявленный деструктор не является виртуальным.

When should I be using void operator delete( void *, size_t );

Если вы хотите, чтобы размер, который был выделен, был известен в операторе delete. Я писал о том, что это значит здесь: Что делает новый оператор C++, кроме выделения и вызова ctor?. Если вы используете (из вашего перегруженного оператора-члена delete / new) глобальный оператор new и delete, чтобы получить вашу память и освободить ее, или даже malloc / free, вам не нужна эта информация о размере. Но это может быть полезно для ведения журнала.

Не обращайте внимания на комментарий, который я только что удалил. Так есть ли польза от использования оператора void delete (void *, size_t); больше sizeof (имя класса)?

BigSandwich 03.01.2009 02:05

Ах, неважно. Я предполагаю, что new () может выделить любой размер, поэтому sizeof (classname) может дать вам неправильный размер. В моем случае; однако я думаю, что они эквивалентны. Спасибо.

BigSandwich 03.01.2009 02:18

если вы не используете форму массива, она должна точно выделить sizeof (T). поэтому size_t вашего удаления всегда должен быть точно sizeof (T) пока не, вы фактически удаляете память производного класса. (что происходит, если производный класс не имеет оператора delete)

Johannes Schaub - litb 03.01.2009 02:19

@ JohannesSchaub-litb Разве это не все о концепции областей видимости по отношению к классам? Я имею в виду, что когда вызывается delete, оно ищет подходящую версию в области производного класса, и, поскольку она находит ее, вызывается эта версия. Это внутренний смысл того, что вы сказали: «Если использовался оператор new производного класса, будет также использован его оператор delete». Пожалуйста, поправьте меня, если я ошибаюсь.

ubuntugod 23.02.2016 10:27

(эй, я должен сначала написать, а потом посмотреть :))

Вот соответствующие выдержки из Стандарта:

1 Оператор удаления-выражения уничтожает самый производный объект (intro.object) или массив, созданный новым выражением. удалить-выражение: :: opt delete cast-expression :: opt delete [] выражение-выражение Первая альтернатива предназначена для объектов, не являющихся массивами, а вторая - для массивы. Операнд должен иметь тип указателя или тип класса, имеющий единственная функция преобразования (class.conv.fct) в тип указателя. Результат имеет тип void.

3 В первом варианте (удалить объект), если статический тип объекта операнд отличается от своего динамического типа, статический тип должен быть базовый класс динамического типа операнда, а статический тип должен есть виртуальный деструктор или поведение не определено. Во втором альтернатива (удалить массив), если динамический тип объекта удаленный отличается от своего статического типа, поведение не определено.19)

«эй, я должен сначала опубликовать, а посмотреть позже», безусловно, хорошая идея: p у вас есть 5 минут, чтобы исправить неправильные вещи, прежде чем появится метка «отредактировано»: DD

Johannes Schaub - litb 03.01.2009 01:51

Другие вопросы по теме