TN017: Menghancurkan objek jendela
Catatan ini menjelaskan penggunaan CWnd::PostNcDestroy
metode . Gunakan metode ini jika Anda ingin melakukan alokasi objek -turunan CWnd
yang disesuaikan. Catatan ini juga menjelaskan mengapa Anda harus menggunakan CWnd::DestroyWindow
untuk menghancurkan objek C++ Windows alih-alih delete
operator.
Jika Anda mengikuti panduan dalam artikel ini, Anda akan memiliki beberapa masalah pembersihan. Masalah ini dapat disebabkan oleh masalah seperti lupa menghapus/membebaskan memori C++, lupa untuk membebaskan sumber daya sistem seperti HWND
s, atau membebaskan objek terlalu banyak kali.
Masalahnya
Setiap objek windows (objek kelas yang berasal dari CWnd
) mewakili objek C++ dan HWND
. Objek C++ dialokasikan dalam timbunan aplikasi dan HWND
dialokasikan dalam sumber daya sistem oleh manajer jendela. Karena ada beberapa cara untuk menghancurkan objek jendela, kita harus menyediakan seperangkat aturan yang mencegah kebocoran sumber daya sistem atau memori. Aturan ini juga harus mencegah objek dan handel Windows dihancurkan lebih dari satu kali.
Menghancurkan jendela
Berikut ini adalah dua cara yang diizinkan untuk menghancurkan objek Windows:
Memanggil
CWnd::DestroyWindow
atau WINDOWS APIDestroyWindow
.Menghapus secara eksplisit dengan
delete
operator.
Kasus pertama sejauh ini adalah yang paling umum. Kasus ini berlaku bahkan jika kode Anda tidak memanggil DestroyWindow
secara langsung. Ketika pengguna langsung menutup jendela bingkai, tindakan ini menghasilkan pesan WM_CLOSE, dan respons default terhadap pesan ini adalah memanggil DestroyWindow
. Ketika jendela induk dihancurkan, Windows memanggil DestroyWindow
semua anaknya.
Kasus kedua, penggunaan delete
operator pada objek Windows, harus jarang terjadi. Berikut ini adalah beberapa kasus di mana penggunaan delete
adalah pilihan yang benar.
Pembersihan otomatis dengan CWnd::PostNcDestroy
Ketika sistem menghancurkan jendela Windows, pesan Windows terakhir yang dikirim ke jendela adalah WM_NCDESTROY
. Handler default CWnd
untuk pesan tersebut adalah CWnd::OnNcDestroy
. OnNcDestroy
akan melepaskan HWND
dari objek C++ dan memanggil fungsi PostNcDestroy
virtual . Beberapa kelas mengambil alih fungsi ini untuk menghapus objek C++.
Implementasi CWnd::PostNcDestroy
default tidak melakukan apa pun, yang sesuai untuk objek jendela yang dialokasikan pada bingkai tumpukan atau disematkan di objek lain. Perilaku ini tidak sesuai untuk objek jendela yang dirancang untuk alokasi pada timbunan tanpa objek lain. Dengan kata lain, tidak sesuai untuk objek jendela yang tidak disematkan di objek C++ lainnya.
Kelas yang dirancang untuk alokasi saja pada timbunan PostNcDestroy
mengambil alih metode untuk melakukan delete this;
. Pernyataan ini akan membebaskan memori apa pun yang terkait dengan objek C++. Meskipun destruktor default CWnd
memanggil DestroyWindow
jika m_hWnd
tidak NULL
, panggilan ini tidak menyebabkan rekursi tak terbatas karena handel akan dilepaskan dan NULL
selama fase pembersihan.
Catatan
Sistem biasanya memanggil CWnd::PostNcDestroy
setelah memproses pesan Windows WM_NCDESTROY
dan HWND
dan objek jendela C++ tidak lagi tersambung. Sistem juga akan memanggil CWnd::PostNcDestroy
dalam implementasi sebagian besar CWnd::Create
panggilan jika kegagalan terjadi. Aturan pembersihan otomatis dijelaskan nanti dalam artikel ini.
Kelas pembersihan otomatis
Kelas berikut tidak dirancang untuk pembersihan otomatis. Mereka biasanya disematkan di objek C++ lain atau pada tumpukan:
Semua kontrol Windows standar (
CStatic
, ,CEdit
CListBox
, dan sebagainya).Setiap jendela anak berasal langsung dari
CWnd
(misalnya, kontrol kustom).Jendela pemisah (
CSplitterWnd
).Bilah kontrol default (kelas yang berasal dari
CControlBar
, lihat Catatan Teknis 31 untuk mengaktifkan penghapusan otomatis untuk objek bilah kontrol).Dialog (
CDialog
) yang dirancang untuk dialog modal pada bingkai tumpukan.Semua dialog standar kecuali
CFindReplaceDialog
.Dialog default yang dibuat oleh ClassWizard.
Kelas berikut dirancang untuk pembersihan otomatis. Mereka biasanya dialokasikan sendiri di timbunan:
Jendela bingkai utama (diturunkan secara langsung atau tidak langsung dari
CFrameWnd
).Lihat jendela (diturunkan secara langsung atau tidak langsung dari
CView
).
Jika Anda ingin melanggar aturan ini, Anda harus mengambil alih PostNcDestroy
metode di kelas turunan Anda. Untuk menambahkan pembersihan otomatis ke kelas Anda, panggil kelas dasar Anda lalu lakukan delete this;
. Untuk menghapus pembersihan otomatis dari kelas Anda, hubungi CWnd::PostNcDestroy
langsung alih-alih PostNcDestroy
metode kelas dasar langsung Anda.
Penggunaan paling umum untuk mengubah perilaku pembersihan otomatis adalah membuat dialog tanpa mode yang dapat dialokasikan pada timbunan.
Kapan harus memanggil delete
Kami menyarankan agar Anda memanggil DestroyWindow
untuk menghancurkan objek Windows, baik metode C++ atau API global DestroyWindow
.
Jangan panggil API global DestroyWindow
untuk menghancurkan jendela MDI Child. Anda harus menggunakan metode CWnd::DestroyWindow
virtual sebagai gantinya.
Untuk objek C++ Window yang tidak melakukan pembersihan otomatis, menggunakan delete
operator dapat menyebabkan kebocoran memori saat Anda mencoba memanggil DestroyWindow
di CWnd::~CWnd
destruktor jika VTBL
tidak menunjuk ke kelas turunan yang benar. Kebocoran terjadi karena sistem tidak dapat menemukan metode penghancurkan yang sesuai untuk dipanggil. Menggunakan DestroyWindow
alih-alih delete
menghindari masalah ini. Karena kesalahan ini bisa halus, mengkompilasi dalam mode debug akan menghasilkan peringatan berikut jika Anda berisiko.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
Untuk objek C++ Windows yang melakukan pembersihan otomatis, Anda harus memanggil DestroyWindow
. Jika Anda menggunakan operator secara delete
langsung, alokator memori diagnostik MFC akan memberi tahu Anda bahwa Anda membebaskan memori dua kali. Dua kemunculan adalah panggilan eksplisit pertama Anda dan panggilan tidak langsung ke delete this;
dalam implementasi pembersihan PostNcDestroy
otomatis .
Setelah Anda memanggil DestroyWindow
objek pembersihan non-otomatis, objek C++ masih ada, tetapi m_hWnd
akan menjadi NULL
. Setelah Anda memanggil DestroyWindow
objek pembersihan otomatis, objek C++ akan hilang, dibebaskan oleh operator penghapusan C++ dalam implementasi pembersihan PostNcDestroy
otomatis .
Baca juga
Catatan teknis menurut angka
Catatan teknis menurut kategori