Проблема, с которой я сталкиваюсь, заключается в том, что, насколько мне известно, оператор удаления должен быть статической функцией, но иногда компилятор (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 * );
если это стандартное поведение?





Это определенно стандартное поведение. Если использовался оператор 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, вам не нужна эта информация о размере. Но это может быть полезно для ведения журнала.
Ах, неважно. Я предполагаю, что new () может выделить любой размер, поэтому sizeof (classname) может дать вам неправильный размер. В моем случае; однако я думаю, что они эквивалентны. Спасибо.
если вы не используете форму массива, она должна точно выделить sizeof (T). поэтому size_t вашего удаления всегда должен быть точно sizeof (T) пока не, вы фактически удаляете память производного класса. (что происходит, если производный класс не имеет оператора delete)
@ JohannesSchaub-litb Разве это не все о концепции областей видимости по отношению к классам? Я имею в виду, что когда вызывается delete, оно ищет подходящую версию в области производного класса, и, поскольку она находит ее, вызывается эта версия. Это внутренний смысл того, что вы сказали: «Если использовался оператор new производного класса, будет также использован его оператор delete». Пожалуйста, поправьте меня, если я ошибаюсь.
(эй, я должен сначала написать, а потом посмотреть :))
Вот соответствующие выдержки из Стандарта:
1 Оператор удаления-выражения уничтожает самый производный объект (intro.object) или массив, созданный новым выражением. удалить-выражение: :: opt delete cast-expression :: opt delete [] выражение-выражение Первая альтернатива предназначена для объектов, не являющихся массивами, а вторая - для массивы. Операнд должен иметь тип указателя или тип класса, имеющий единственная функция преобразования (class.conv.fct) в тип указателя. Результат имеет тип void.
3 В первом варианте (удалить объект), если статический тип объекта операнд отличается от своего динамического типа, статический тип должен быть базовый класс динамического типа операнда, а статический тип должен есть виртуальный деструктор или поведение не определено. Во втором альтернатива (удалить массив), если динамический тип объекта удаленный отличается от своего статического типа, поведение не определено.19)
«эй, я должен сначала опубликовать, а посмотреть позже», безусловно, хорошая идея: p у вас есть 5 минут, чтобы исправить неправильные вещи, прежде чем появится метка «отредактировано»: DD
Не обращайте внимания на комментарий, который я только что удалил. Так есть ли польза от использования оператора void delete (void *, size_t); больше sizeof (имя класса)?