Próbowałem wezwać ::delete
klasę operator delete
. Ale destruktor nie jest nazywany.
I zdefiniowano klasę MyClass
którego operator delete
został przeciążony. Globalny operator delete
jest również przeciążony. Przeciążonej operator delete
z MyClass
wezwie przeciążonej globalny 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;
}
Dane wyjściowe to:
Newing MyClass...
Global newing...
Constructing MyClass...
End of newing MyClass...
Constructing MyClass...
Destroying MyClass...
Deleting MyClass...
Global deleting...
End of deleting MyClass...
Rzeczywisty:
Jest tylko jedno wywołanie destruktora przed wywołaniem przeciążony operator delete
od MyClass
.
Spodziewany:
Istnieją dwa połączenia z destruktorem. Jeden przed wywołaniem przeciążony operator delete
od MyClass
. Kolejny przed wezwaniem globalnego operator delete
.
::delete p;
powoduje niezdefiniowane zachowanie, ponieważ typ *p
nie jest taki sam jak typ usuwanego obiektu (ani klasa bazowa z wirtualnym destruktorem)
void*
ponieważ operand jest nawet wyraźnie źle sformułowany. [expr.delete] / 1 : " Operand będzie wskazywał na typ obiektu lub typ klasy. [...] Oznacza to, że obiektu nie można usunąć za pomocą wskaźnika typu void, ponieważ void nie jest typem obiektu. * „@OP Poprawiłem swoją odpowiedź.
MyClass::operator new()
powinien przydzielić pamięć surową (przynajmniej)size
bajtów. Nie powinna próbować całkowicie zbudować instancjiMyClass
. KonstruktorMyClass
jest wykonywany poMyClass::operator new()
. Następniedelete
wyrażenie wmain()
wywołuje destruktor i zwalnia pamięć (bez ponownego wywoływania destruktora).::delete p
Wyrażenie nie posiada informacji na temat rodzaju obiektówp
wskazuje na, ponieważp
jestvoid *
, więc nie może wywołać destruktor.