Bagikan melalui


TN017: Menghancurkan objek jendela

Catatan ini menjelaskan penggunaan CWnd::PostNcDestroy metode . Gunakan metode ini jika Anda ingin melakukan alokasi objek -turunan CWndyang 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 HWNDs, 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 HWNDdialokasikan 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 API DestroyWindow.

  • 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 PostNcDestroyvirtual . 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, , CEditCListBox, 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 PostNcDestroyotomatis .

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 PostNcDestroyotomatis .

Baca juga

Catatan teknis menurut angka
Catatan teknis menurut kategori