Aracılığıyla paylaş


TN017: Pencere nesnelerini yok etme

Bu not, yönteminin CWnd::PostNcDestroy kullanımını açıklar. Türetilmiş nesnelerin özelleştirilmiş ayırmasını CWndyapmak istiyorsanız bu yöntemi kullanın. Bu not, işleç yerine delete bir C++ Windows nesnesini yok etmek için neden kullanmanız CWnd::DestroyWindow gerektiğini de açıklar.

Bu makaledeki yönergeleri izlerseniz, birkaç temizleme sorununuz olacaktır. Bu sorunlar C++ belleği silmeyi/boşaltmayı unutma, s gibi HWNDsistem kaynaklarını boşaltmayı unutma veya nesneleri çok fazla serbest bırakma gibi sorunlardan kaynaklanabilir.

Sorun

Her windows nesnesi (öğesinden CWndtüretilen bir sınıfın nesnesi) hem C++ nesnesini hem de bir HWNDöğesini temsil eder. C++ nesneleri uygulamanın yığınında HWNDve sistem kaynaklarında pencere yöneticisi tarafından ayrılır. Bir pencere nesnesini yok etmenin çeşitli yolları olduğundan, sistem kaynağı veya bellek sızıntılarını önleyen bir dizi kural sağlamamız gerekir. Bu kurallar, nesnelerin ve Windows tanıtıcılarının birden çok kez yok edilmesini de engellemelidir.

Pencereleri yok etme

Bir Windows nesnesini yok etmek için izin verilen iki yol şunlardır:

  • veya Windows API'sini DestroyWindowçağırmaCWnd::DestroyWindow.

  • işleciyle delete açıkça siliniyor.

İlk durum açık ara en yaygın olanıdır. Kodunuz doğrudan çağrılmıyor DestroyWindow olsa bile bu durum geçerlidir. Kullanıcı bir çerçeve penceresini doğrudan kapattığında, bu eylem WM_CLOSE iletisini oluşturur ve bu iletiye verilen varsayılan yanıt öğesini çağırmaktır DestroyWindow. Bir üst pencere yok edildiğinde, Windows tüm alt öğelerini çağırır DestroyWindow .

İkinci durumda, Windows nesnelerinde işlecin kullanımı delete nadir olmalıdır. Aşağıdakiler, kullanımın delete doğru seçim olduğu bazı durumlardır.

Ile otomatik temizleme CWnd::PostNcDestroy

Sistem bir Windows penceresini yok ettiğinde, pencereye gönderilen son Windows iletisi şeklindedir WM_NCDESTROY. Bu iletinin varsayılan CWnd işleyicisi şeklindedir CWnd::OnNcDestroy. OnNcDestroy , C++ nesnesinden öğesini ayıracak HWND ve sanal işlevini PostNcDestroyçağıracaktır. Bazı sınıflar C++ nesnesini silmek için bu işlevi geçersiz kılar.

varsayılan uygulaması CWnd::PostNcDestroy , yığın çerçevesinde ayrılan veya diğer nesnelere eklenmiş pencere nesneleri için uygun olan hiçbir şey yapmaz. Bu davranış, başka nesne olmadan yığında ayırma için tasarlanmış pencere nesneleri için uygun değildir. Başka bir deyişle, diğer C++ nesnelerine eklenmemiş pencere nesneleri için uygun değildir.

Yığında tek başına ayırma için tasarlanmış sınıflar, yöntemini geçersiz kılarak PostNcDestroy bir delete this;gerçekleştirebilir. Bu deyim, C++ nesnesiyle ilişkili tüm bellekleri serbest bırakır. Varsayılan CWnd yıkıcı değilse çağırsa NULLDestroyWindow m_hWnd da, tutamaç ayrılacağından ve NULL temizleme aşamasında olduğundan bu çağrı sonsuz özyinelemelere yol açmaz.

Dekont

Sistem genellikle Windows WM_NCDESTROY iletisini işledikten sonra çağırır CWnd::PostNcDestroy ve HWND ve C++ pencere nesnesi artık bağlı değildir. Sistem, hata oluşursa çoğu CWnd::Create çağrının uygulanmasında da çağrı CWnd::PostNcDestroy yapacaktır. Otomatik temizleme kuralları bu makalenin devamında açıklanmıştır.

Otomatik temizleme sınıfları

Aşağıdaki sınıflar otomatik temizleme için tasarlanmamıştır. Bunlar genellikle diğer C++ nesnelerine veya yığına eklenir:

  • Tüm standart Windows denetimleri (CStatic, CEdit, CListBoxvb.).

  • Doğrudan öğesinden CWnd türetilen tüm alt pencereler (örneğin, özel denetimler).

  • Bölücü pencereler (CSplitterWnd).

  • Varsayılan denetim çubukları ('den CControlBartüretilen sınıflar, denetim çubuğu nesneleri için otomatik silmeyi etkinleştirmeye yönelik Teknik Not 31'e bakın).

  • Yığın çerçevesindeki kalıcı iletişim kutuları için tasarlanmış iletişim kutuları (CDialog).

  • dışındaki CFindReplaceDialogtüm standart iletişim kutuları.

  • ClassWizard tarafından oluşturulan varsayılan iletişim kutuları.

Aşağıdaki sınıflar otomatik temizleme için tasarlanmıştır. Bunlar genellikle yığında kendileri tarafından ayrılır:

  • Ana çerçeve pencereleri (doğrudan veya dolaylı olarak öğesinden CFrameWndtüretilir).

  • Pencereleri görüntüleme (doğrudan veya dolaylı olarak öğesinden CViewtüretilir).

Bu kuralları bozmak istiyorsanız, türetilmiş sınıfınızda yöntemini geçersiz kılmanız PostNcDestroy gerekir. Sınıfınıza otomatik temizleme eklemek için temel sınıfınızı çağırın ve ardından bir delete this;yapın. Otomatik temizlemeyi sınıfınızdan kaldırmak için doğrudan temel sınıfınızın yöntemi yerine PostNcDestroy doğrudan çağrısı CWnd::PostNcDestroy yapın.

Otomatik temizleme davranışını değiştirmenin en yaygın kullanımı, yığında ayrılabilecek bir modsuz iletişim kutusu oluşturmaktır.

Ne zaman aranacak? delete

C++ yöntemi veya genel DestroyWindow API'si gibi bir Windows nesnesini yok etmek için çağırmanızı DestroyWindow öneririz.

MDI Alt penceresini yok etmek için genel DestroyWindow API'yi çağırmayın. Bunun yerine sanal yöntemi CWnd::DestroyWindow kullanmanız gerekir.

Otomatik temizleme gerçekleştirmeyen C++ Pencere nesneleri için işlecini delete kullanmak, doğru türetilmiş sınıfı göstermiyorsa yıkıcıyı CWnd::~CWnd çağırmaya DestroyWindow çalıştığınızda bellek sızıntısına VTBL neden olabilir. Sızıntı, sistemin çağıracak uygun yok etme yöntemini bulamadığı için oluşur. yerine DestroyWindow kullanmak delete bu sorunlardan kaçınıyor. Bu hata hafif olabileceğinden hata ayıklama modunda derleme, risk altındaysanız aşağıdaki uyarıyı oluşturur.

Warning: calling DestroyWindow in CWnd::~CWnd
    OnDestroy or PostNcDestroy in derived class will not be called

Otomatik temizleme gerçekleştiren C++ Windows nesneleri için öğesini çağırmalısınız DestroyWindow. işlecini delete doğrudan kullanırsanız, MFC tanılama belleği ayırıcısı belleği iki kez boşalttığınız konusunda sizi bilgilendirir. İki oluşum, otomatik temizleme uygulamasındaki ilk açık çağrınız ve dolaylı çağrısıdır delete this; PostNcDestroy.

Otomatik olmayan bir temizleme nesnesini çağırdıktan DestroyWindow sonra, C++ nesnesi yine etrafta olur, ancak m_hWnd olur NULL. Bir otomatik temizleme nesnesini çağırdıktan DestroyWindow sonra, C++ nesnesi gider ve C++ silme işleci tarafından otomatik temizleme uygulamasında PostNcDestroyserbest kalır.

Ayrıca bkz.

Numaraya göre teknik notlar
Kategoriye göre teknik notlar