TN017: уничтожение объектов окна
В этом примечании описывается использование CWnd::PostNcDestroy
метода. Используйте этот метод, если вы хотите выполнить настраиваемое выделение производных CWnd
объектов. В этом примечании также объясняется, почему следует использовать CWnd::DestroyWindow
для уничтожения объекта Windows C++ вместо delete
оператора.
Если вы следуйте рекомендациям, описанным в этой статье, у вас будет мало проблем с очисткой. Эти проблемы могут привести к таким проблемам, как забыв удалить или освободить память C++, забыв освободить системные ресурсы, такие как HWND
s, или освободить объекты слишком много раз.
задачи;
Каждый объект Windows (объект класса, производный от CWnd
) представляет как объект C++, так и объект HWND
. Объекты C++ выделяются в куче приложения и HWND
выделяются в системных ресурсах диспетчером окон. Так как существует несколько способов уничтожения объекта окна, необходимо предоставить набор правил, которые препятствуют утечке системного ресурса или памяти. Эти правила также должны препятствовать уничтожению объектов и дескрипторов Windows.
Уничтожение окон
Ниже приведены два разрешенных способа уничтожения объекта Windows:
Вызов
CWnd::DestroyWindow
или APIDestroyWindow
Windows.Явное удаление с
delete
помощью оператора.
Первый случай является самым распространенным. Этот случай применяется, даже если код не вызывается DestroyWindow
напрямую. Когда пользователь закрывает окно кадра, это действие создает сообщение WM_CLOSE и ответ по умолчанию на это сообщение вызывается DestroyWindow
. При уничтожении родительского окна Windows вызывает DestroyWindow
все дочерние элементы.
Во втором случае использование оператора в объектах delete
Windows должно быть редким. Ниже приведены некоторые случаи, когда использование delete
является правильным выбором.
Автоматическая очистка с помощью CWnd::PostNcDestroy
Когда система уничтожает окно Windows, последнее сообщение Windows отправляется WM_NCDESTROY
в окно. Обработчик по умолчанию CWnd
для этого сообщения CWnd::OnNcDestroy
. OnNcDestroy
отсоединит HWND
объект C++ и вызовет виртуальную функцию PostNcDestroy
. Некоторые классы переопределяют эту функцию, чтобы удалить объект C++.
Реализация по умолчанию CWnd::PostNcDestroy
не делает ничего, что подходит для объектов окна, выделенных на кадре стека или внедренных в другие объекты. Это поведение не подходит для объектов окон, предназначенных для выделения в куче без других объектов. Другими словами, он не подходит для объектов окон, которые не внедрены в другие объекты C++.
Классы, предназначенные только для выделения в куче, переопределяют PostNcDestroy
метод для выполнения delete this;
. Эта инструкция освобождает любую память, связанную с объектом C++. Несмотря на то что деструктор по умолчанию CWnd
вызывается, если m_hWnd
это не NULL
так, этот вызов не приводит к бесконечному рекурсии, так как дескриптор DestroyWindow
будет отсоединен и NULL
во время этапа очистки.
Примечание.
Система обычно вызывает CWnd::PostNcDestroy
сообщение Windows WM_NCDESTROY
и HWND
объект окна C++ больше не подключен. Система также вызывается CWnd::PostNcDestroy
в реализации большинства CWnd::Create
вызовов, если происходит сбой. Правила автоматической очистки описаны далее в этой статье.
Классы автоматической очистки
Следующие классы не предназначены для автоматической очистки. Обычно они внедрены в другие объекты C++ или на стеке:
Все стандартные элементы управления Windows (
CStatic
,CEdit
иCListBox
т. д.).Все дочерние окна, производные непосредственно от
CWnd
(например, пользовательских элементов управления).Разделитель окон (
CSplitterWnd
).Панели управления по умолчанию (классы, производные от
CControlBar
, см . Технический примечание 31 для включения автоматического удаления для объектов панели управления).Диалоги (
CDialog
) предназначены для модальных диалогов в кадре стека.Все стандартные диалоги, кроме
CFindReplaceDialog
.Диалоги по умолчанию, созданные ClassWizard.
Следующие классы предназначены для автоматической очистки. Они обычно выделяются сами по себе в куче:
Окна главного кадра (производные напрямую или косвенно от
CFrameWnd
).Просмотр окон (производных напрямую или косвенно от
CView
).
Если вы хотите нарушить эти правила, необходимо переопределить PostNcDestroy
метод в производном классе. Чтобы добавить автоматическую очистку в класс, вызовите базовый класс и выполните команду delete this;
. Чтобы удалить автоматическую очистку из класса, вызовите CWnd::PostNcDestroy
непосредственно вместо PostNcDestroy
метода прямого базового класса.
Наиболее распространенным способом изменения поведения автоматической очистки является создание бессерверного диалога, которое можно выделить в куче.
Когда следует вызывать метод delete
Рекомендуется уничтожить DestroyWindow
объект Windows, метод C++ или глобальный DestroyWindow
API.
Не вызывайте глобальный DestroyWindow
API для уничтожения дочернего окна MDI. Вместо этого следует использовать виртуальный метод CWnd::DestroyWindow
.
Для объектов окна C++, которые не выполняют автоматическую очистку, оператор delete
может вызвать утечку памяти при попытке вызвать DestroyWindow
деструктор, если VTBL
он не указывает на правильный CWnd::~CWnd
производный класс. Утечка возникает, так как система не может найти соответствующий метод уничтожения для вызова. Использование DestroyWindow
вместо того, чтобы delete
избежать этих проблем. Так как эта ошибка может быть тонкой, компиляция в режиме отладки приведет к возникновению следующего предупреждения при возникновении риска.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
Для объектов Windows C++, выполняющих автоматическую очистку, необходимо вызвать DestroyWindow
. Если оператор используется delete
напрямую, средство выделения памяти диагностики MFC уведомит вас о том, что вы освобождаете память два раза. Два вхождения — это первый явный вызов и косвенный вызов delete this;
в реализации автоматической очистки PostNcDestroy
.
После вызова DestroyWindow
объекта, отличного от автоматической очистки, объект C++ по-прежнему будет находиться вокруг, но m_hWnd
будет.NULL
После вызова DestroyWindow
объекта автоматической очистки объект C++ будет удален оператором удаления C++ в реализации автоматической очистки PostNcDestroy
.
См. также
Технические заметки по числу
Технические заметки по категориям