Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом примечании описывается использование CWnd::PostNcDestroy
метода. Используйте этот метод, если вы хотите выполнить настраиваемое выделение производных CWnd
объектов. В этом примечании также объясняется, почему следует использовать CWnd::DestroyWindow
для уничтожения объекта Windows C++ вместо delete
оператора.
Если вы следуйте рекомендациям, описанным в этой статье, у вас будет мало проблем с очисткой. Эти проблемы могут привести к таким проблемам, как забыв удалить или освободить память C++, забыв освободить системные ресурсы, такие как HWND
s, или освободить объекты слишком много раз.
задачи;
Каждый объект Windows (объект класса, производный от CWnd
) представляет как объект C++, так и объект HWND
. Объекты C++ выделяются в куче приложения, а элементы HWND
выделяются в системных ресурсах менеджером окон. Так как существует несколько способов уничтожения объекта окна, необходимо предоставить набор правил, которые препятствуют утечке системного ресурса или памяти. Эти правила также должны предотвращать уничтожение объектов и дескрипторов Windows более одного раза.
Уничтожение окон
Ниже приведены два разрешенных способа уничтожения объекта Windows:
Вызов
CWnd::DestroyWindow
или Windows APIDestroyWindow
.Явное удаление с помощью оператора
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
вызывает DestroyWindow
если m_hWnd
не является NULL
, этот вызов не приводит к бесконечной рекурсии, так как дескриптор будет отсоединен и NULL
во время этапа очистки.
Замечание
Система обычно вызывает CWnd::PostNcDestroy
после обработки сообщения Windows WM_NCDESTROY
, и объект окна C++ HWND
больше не подключен. Система также будет вызывать 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++ или глобальный API DestroyWindow
.
Не вызывайте глобальный API DestroyWindow
для удаления дочернего окна MDI. Вместо этого следует использовать виртуальный метод CWnd::DestroyWindow
.
Для объектов окна C++, которые не выполняют автоматическую очистку, оператор delete
может вызвать утечку памяти при попытке вызвать DestroyWindow
в деструкторе CWnd::~CWnd
, если VTBL
не указывает на правильный производный класс. Утечка возникает, так как система не может найти соответствующий метод уничтожения для вызова. Использование 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
.
См. также
Технические заметки по номеру
Технические заметки по категориям