TN017: Pencere nesnelerini yok etme
Bu not, yönteminin CWnd::PostNcDestroy
kullanımını açıklar. Türetilmiş nesnelerin özelleştirilmiş ayırmasını CWnd
yapmak 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 HWND
sistem kaynaklarını boşaltmayı unutma veya nesneleri çok fazla serbest bırakma gibi sorunlardan kaynaklanabilir.
Sorun
Her windows nesnesi (öğesinden CWnd
türetilen bir sınıfın nesnesi) hem C++ nesnesini hem de bir HWND
öğesini temsil eder. C++ nesneleri uygulamanın yığınında HWND
ve 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 NULL
DestroyWindow
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
,CListBox
vb.).Doğrudan öğesinden
CWnd
türetilen tüm alt pencereler (örneğin, özel denetimler).Bölücü pencereler (
CSplitterWnd
).Varsayılan denetim çubukları ('den
CControlBar
tü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
CFindReplaceDialog
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 kendileri tarafından ayrılır:
Ana çerçeve pencereleri (doğrudan veya dolaylı olarak öğesinden
CFrameWnd
türetilir).Pencereleri görüntüleme (doğrudan veya dolaylı olarak öğesinden
CView
tü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 PostNcDestroy
serbest kalır.