Я пытался вызвать ::delete
класс в operator delete
этом. Но деструктор не называется.
Я определил класс MyClass
, operator delete
который был перегружен. Глобал operator delete
также перегружен. Перегруженный operator delete
из MyClass
будет вызывать перегруженный глобальный operator delete
.
class MyClass
{
public:
MyClass() { printf("Constructing MyClass...\n"); }
virtual ~MyClass() { printf("Destroying MyClass...\n"); }
void* operator new(size_t size)
{
printf("Newing MyClass...\n");
void* p = ::new MyClass();
printf("End of newing MyClass...\n");
return p;
}
void operator delete(void* p)
{
printf("Deleting MyClass...\n");
::delete p; // Why is the destructor not called here?
printf("End of deleting MyClass...\n");
}
};
void* operator new(size_t size)
{
printf("Global newing...\n");
return malloc(size);
}
void operator delete(void* p)
{
printf("Global deleting...\n");
free(p);
}
int main(int argc, char** argv)
{
MyClass* myClass = new MyClass();
delete myClass;
return EXIT_SUCCESS;
}
Выход:
Newing MyClass...
Global newing...
Constructing MyClass...
End of newing MyClass...
Constructing MyClass...
Destroying MyClass...
Deleting MyClass...
Global deleting...
End of deleting MyClass...
Актуально:
Существует только один вызов деструктора перед вызовом перегружен operator delete
из MyClass
.
Ожидаемое:
Есть два вызова деструктора. Один перед вызовом перегружен operator delete
из MyClass
. Еще один, прежде чем назвать глобальным operator delete
.
c++
delete-operator
expinc
источник
источник
MyClass::operator new()
должен выделять необработанную память, из (как минимум)size
байтов. Он не должен пытаться полностью создать экземплярMyClass
. КонструкторMyClass
выполняется послеMyClass::operator new()
. Затемdelete
выражение inmain()
вызывает деструктор и освобождает память (без повторного вызова деструктора).::delete p
Выражение не имеет никакой информации о типе объектаp
точек на, так какp
этоvoid *
, так что не может вызывать деструктор.::delete p;
вызывает неопределенное поведение, так как тип*p
не совпадает с типом удаляемого объекта (ни базовый класс с виртуальным деструктором)void*
операнд даже явно плохо сформирован. [expr.delete] / 1 : " Операнд должен иметь указатель на тип объекта или тип класса. [...] Это означает, что объект нельзя удалить с помощью указателя типа void, поскольку void не является типом объекта. * "@OP Я исправил свой ответ.Ответы:
Вы злоупотребляете
operator new
иoperator delete
. Эти операторы являются функциями выделения и освобождения. Они не несут ответственности за строительство или разрушение объектов. Они отвечают только за предоставление памяти, в которую будет помещен объект.Глобальные версии этих функций
::operator new
и::operator delete
.::new
и::delete
новые / delete-выражения, как естьnew
/delete
, отличаются от тех, что::new
и::delete
будут обходить специфичные для классаoperator new
/operator delete
перегрузки.Выражения new / delete-выражений конструируют / уничтожают и выделяют / освобождают (вызывая соответствующие
operator new
илиoperator delete
до конструирования, или после уничтожения).Поскольку ваша перегрузка отвечает только за часть выделения / освобождения, она должна вызывать
::operator new
и::operator delete
вместо::new
и::delete
.delete
Вdelete myClass;
отвечает за вызов деструктора.::delete p;
не вызывает деструктор, потому чтоp
имеет тип,void*
и поэтому выражение не может знать, какой деструктор вызвать. Вероятно, он будет вызывать вашу замену::operator delete
для освобождения памяти, хотя использованиеvoid*
операнда as для выражения удаления некорректно (см. Правку ниже).::new MyClass();
вызывает вашу замену,::operator new
чтобы выделить память и создать в ней объект. Указатель на этот объект возвращается какvoid*
новое выражение вMyClass* myClass = new MyClass();
, которое затем создаст другой объект в этой памяти, заканчивая время жизни предыдущего объекта, не вызывая его деструктор.Редактировать:
Благодаря комментарию @MM к этому вопросу, я понял, что
void*
операнд в as на::delete
самом деле плохо сформирован. ( [expr.delete] / 1 ) Однако основные компиляторы, похоже, решили только предупредить об этом, а не об ошибке. Перед тем как это было сделано плохо сформированным, используя::delete
наvoid*
было уже непредсказуемое поведение, см этот вопрос .Следовательно, ваша программа плохо сформирована, и у вас нет никаких гарантий, что код действительно делает то, что я описал выше, если ему все же удалось скомпилировать.
Как указывает @SanderDeDycker ниже своего ответа, у вас также есть неопределенное поведение, потому что при создании другого объекта в памяти, который уже содержит
MyClass
объект, без вызова деструктора этого объекта, вы нарушаете [basic.life] / 5, что запрещает делать это, если Программа зависит от побочных эффектов деструктора. В этом случаеprintf
утверждение в деструкторе имеет такой побочный эффект.источник
Ваши специфичные для класса перегрузки выполняются неправильно. Это видно из вашего вывода: конструктор вызывается дважды!
В конкретном классе
operator new
вызовите глобальный оператор напрямую:Точно так же в классе
operator delete
, выполните:Обратитесь к
operator new
странице справки для более подробной информации.источник
См. Ссылку CPP :
Delete (и new) отвечают только за часть «управление памятью».
Таким образом, ясно и ожидается, что деструктор вызывается только один раз - для очистки экземпляра объекта. Если бы он вызывался дважды, каждый деструктор должен проверить, был ли он уже вызван.
источник
operator delete()
функция - это не то же самое, что выражение удаления. Деструктор вызывается до вызоваoperator delete()
функции.