Saya mencoba menelepon ::delete
untuk kelas di operator delete
dalamnya. Tetapi destruktor tidak disebut.
Saya mendefinisikan kelas MyClass
yang operator delete
kelebihan beban. Global operator delete
juga kelebihan beban. The kelebihan beban operator delete
dari MyClass
akan memanggil global kelebihan beban 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;
}
Outputnya adalah:
Newing MyClass...
Global newing...
Constructing MyClass...
End of newing MyClass...
Constructing MyClass...
Destroying MyClass...
Deleting MyClass...
Global deleting...
End of deleting MyClass...
Sebenarnya:
Hanya ada satu panggilan untuk destructor sebelum memanggil kelebihan beban operator delete
dari MyClass
.
Diharapkan:
Ada dua panggilan ke destructor. Salah satu sebelum memanggil kelebihan beban operator delete
dari MyClass
. Lain sebelum memanggil global operator delete
.
c++
delete-operator
expinc
sumber
sumber
MyClass::operator new()
harus mengalokasikan memori mentah, dari (setidaknya)size
byte. Seharusnya tidak berusaha untuk sepenuhnya membangun contohMyClass
. KonstruktorMyClass
dieksekusi setelahMyClass::operator new()
. Kemudian,delete
ekspresi dimain()
memanggil destruktor, dan melepaskan memori (tanpa memanggil destruktor lagi). The::delete p
ekspresi tidak memiliki informasi tentang jenis objekp
poin di, karenap
merupakanvoid *
, sehingga tidak bisa memanggil destructor.::delete p;
menyebabkan perilaku tidak terdefinisi karena jenis*p
tidak sama dengan jenis objek yang dihapus (atau kelas dasar dengan penghancur virtual)void*
operan bahkan secara eksplisit salah bentuk. [expr.delete] / 1 : " Operand harus dari penunjuk ke tipe objek atau tipe kelas. [...] Ini menyiratkan bahwa suatu objek tidak dapat dihapus menggunakan penunjuk tipe batal karena batal bukan tipe objek. * "@OP Saya telah mengubah jawaban saya.Jawaban:
Anda menyalahgunakan
operator new
danoperator delete
. Operator-operator ini adalah fungsi alokasi dan deallokasi. Mereka tidak bertanggung jawab untuk membangun atau merusak objek. Mereka bertanggung jawab hanya untuk menyediakan memori di mana objek akan ditempatkan.Versi global dari fungsi-fungsi ini adalah
::operator new
dan::operator delete
.::new
dan::delete
yang baru / hapus-ekspresi, sepertinew
/delete
, berbeda dari yang, dalam hal itu::new
dan::delete
akan memotong kelas-spesifikoperator new
/operator delete
overload.Konstruksi baru / hapus-ekspresi / destruksi dan alokasikan / alokasikan (dengan memanggil yang sesuai
operator new
atauoperator delete
sebelum konstruksi atau setelah kehancuran).Karena kelebihan Anda hanya bertanggung jawab untuk bagian alokasi / deallokasi, itu harus memanggil
::operator new
dan::operator delete
bukannya::new
dan::delete
.The
delete
dalamdelete myClass;
bertanggung jawab untuk memanggil destructor.::delete p;
tidak memanggil destruktor karenap
memiliki tipevoid*
dan oleh karena itu ekspresi tidak dapat mengetahui destruktor apa yang harus dipanggil. Mungkin akan memanggil Anda diganti::operator delete
untuk membatalkan alokasi memori, meskipun menggunakanvoid*
operan as untuk menghapus-ekspresi tidak terbentuk (lihat edit di bawah).::new MyClass();
panggilan Anda diganti::operator new
untuk mengalokasikan memori dan membangun objek di dalamnya. Pointer ke objek ini dikembalikanvoid*
ke ekspresi-baru diMyClass* myClass = new MyClass();
, yang kemudian akan membangun objek lain dalam memori ini, mengakhiri masa pakai objek sebelumnya tanpa memanggil destruktornya.Edit:
Berkat komentar @ MM pada pertanyaan itu, saya menyadari bahwa
void*
operan as to not bad::delete
formed. ( [expr.delete] / 1 ) Namun, kompiler utama tampaknya memutuskan untuk hanya memperingatkan tentang ini, bukan kesalahan. Sebelum itu dibuat sakit-terbentuk, menggunakan::delete
padavoid*
perilaku yang sudah terdefinisi punya, lihat pertanyaan ini .Oleh karena itu, program Anda rusak dan Anda tidak memiliki jaminan bahwa kode tersebut benar-benar melakukan apa yang saya jelaskan di atas jika masih berhasil dikompilasi.
Seperti yang ditunjukkan oleh @SanderDeDycker di bawah jawabannya, Anda juga memiliki perilaku tidak terdefinisi karena dengan membangun objek lain di memori yang sudah berisi
MyClass
objek tanpa memanggil destruktor objek itu terlebih dahulu Anda melanggar [basic.life] / 5 yang melarang melakukannya jika Program tergantung pada efek samping destruktor. Dalam hal iniprintf
pernyataan dalam destruktor memiliki efek samping seperti itu.sumber
Kelebihan khusus kelas Anda dilakukan dengan tidak benar. Ini dapat dilihat pada output Anda: konstruktor dipanggil dua kali!
Di kelas khusus
operator new
, hubungi operator global secara langsung:Demikian pula, di kelas khusus
operator delete
, lakukan:Lihat
operator new
halaman referensi untuk lebih jelasnya.sumber
Lihat Referensi CPP :
Hapus (dan baru) hanya bertanggung jawab untuk bagian 'manajemen memori'.
Jadi jelas dan diharapkan bahwa destructor hanya dipanggil sekali - untuk membersihkan instance objek. Apakah itu dipanggil dua kali, setiap destruktor harus memeriksa apakah sudah dipanggil.
sumber
operator delete()
fungsi bukanlah hal yang sama dengan ekspresi delete. Destruktor dipanggil sebelumoperator delete()
fungsi dipanggil.