Aracılığıyla paylaş


TN017: Pencere nesnelerini yok etme

Uyarı

Microsoft Foundation Sınıfları (MFC) kitaplığına destek verilmeye devam ediliyor. Ancak artık özellik eklemeyeceğiz veya belgeleri güncelleştirmeyeceğiz.

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

Bu makaledeki yönergeleri izlerseniz, temizleme sorunlarınız çok az 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 ayrılır ve HWNDsistem kaynaklarında pencere yöneticisi tarafından tahsis edilir. 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 CWnd::DestroyWindowçağırmaDestroyWindow.

  • delete işleciyle açıkça silme işlemi yapılmaktadır.

İlk durum açık ara en yaygın olanıdır. Kodunuz DestroyWindow'yi doğrudan çağırmasa 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 ebeveyn pencere yok edildiğinde, Windows onun tüm alt öğeleri için DestroyWindow çağırır.

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

CWnd::PostNcDestroy ile otomatik temizleme

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

varsayılan CWnd::PostNcDestroy uygulaması hiçbir şey yapmaz, bu da yığın çerçevesinde tahsis edilen veya diğer nesnelere gömülü pencere nesneleri için uygundur. Bu davranış, diğer nesnelere ihtiyaç duymadan yığında ayırmak 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, PostNcDestroy yöntemini geçersiz kılarak 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ı DestroyWindow çağırsa bile, m_hWndNULL değilse, bu çağrı sonsuz özyinelemelere yol açmaz, çünkü tutamaç temizleme aşamasında ayrılacak ve NULL.

Uyarı

Sistem genellikle Windows CWnd::PostNcDestroy iletisini işledikten sonra WM_NCDESTROY çağırır ve HWND ile C++ pencere nesnesi artık birbirine bağlı değildir. Sistem, hata oluşursa çoğu CWnd::PostNcDestroy çağrısının uygulanmasında CWnd::Create işlevini de çağıracaktı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.).

  • CWnd öğesinden doğrudan türetilmiş herhangi bir çocuk pencere (ö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 modlar için tasarlanmış iletişim kutuları (CDialog).

  • CFindReplaceDialog hariç tü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 kendi başlarına ayrılır.

  • Ana çerçeve pencereleri (CFrameWnd'dan doğrudan veya dolaylı olarak türetilmiştir).

  • Pencereyi görüntüle (doğrudan veya dolaylı olarak CView öğesinden türetilir).

Bu kuralları bozmak istiyorsanız, türetilmiş sınıfınızda PostNcDestroy yöntemini geçersiz kılmanız 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. Sınıfınızdan otomatik temizlemeyi kaldırmak için, doğrudan temel sınıfınızın CWnd::PostNcDestroy yöntemi yerine PostNcDestroy'u çağırı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 yapmayan C++ Pencere nesneleri için delete işlecini kullanmak, DestroyWindow doğru türetilmiş sınıfı göstermiyorsa ve CWnd::~CWnd destructor içinde VTBL çağırmaya çalıştığınızda bellek sızıntısına neden olabilir. Sızıntı, sistemin çağırabileceği uygun yok etme metodunu bulamaması nedeniyle oluşur. Bu sorunlardan kaçınmak için DestroyWindow yerine delete kullanmak. 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 yapan C++ Windows nesneleri için DestroyWindow çağrısını yapmanız gerekiyor. 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, delete this;'nin otomatik temizleme uygulamasındaki ilk açık çağrınız ve PostNcDestroy'ye yapılan dolaylı çağrıdır.

Otomatik olmayan bir temizleme nesnesi üzerinde DestroyWindow işlevini çağırdıktan sonra, C++ nesnesi hala var olur, ancak m_hWndNULL olur. Otomatik temizleme nesnesini DestroyWindow ile çağırdıktan sonra, C++ nesnesi kaybolur ve otomatik temizleme uygulamasındaki C++ 'delete' operatörü ile serbest bırakılır.

Ayrıca bakınız

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