TN017. Уничтожение объектов окон
Эта заметка описывается использование метода CWnd::PostNcDestroy. Этот метод следует использовать, если требуется выделение настраиванное задачей CWnd-производные объекты. Эта заметка также объясняется, почему следует использовать CWnd::DestroyWindow для удаления объекта C++ Windows вместо оператора delete.
Если следовать рекомендации в данном разделе, имеется несколько проблем очистки. Эти ошибки могут быть результатом проблем, таких как забывать удаление и освободить память C++ забывать освободить системные ресурсы, HWND s, или выпуска объекты слишком много раз.
Проблема
Каждый объект windows (объект класса, производного от CWnd) и представляет объект C++. HWND. Объекты C++ размещаются в куче приложения и HWND выделяется в системных ресурсах диспетчером окна. Поскольку несколько способов удалить объект окна, нужно предоставить набор правил, которые препятствуют утечки памяти или системных ресурсов. Эти правила должны также предотвратить объекты и дескрипторы Windows из уничтожить несколько раз.
Уничтожения Windows
Следующие 2 использование способа удалить объект Windows:
Вызов CWnd::DestroyWindow или API DestroyWindow Windows.
Удаление явно с помощью оператора delete.
В первом случае безоговорочно наиболее часто. В этом случае применяется даже если ваш код не вызывает DestroyWindow напрямую. Когда пользователь непосредственно закрывает фреймовое окно, это действие создает сообщение WM_CLOSE и ответа по умолчанию к этому сообщению вызова DestroyWindow. при родительское окно уничтожается, Windows вызывает DestroyWindow для всех ее дочерних элементов.
Второе case, использование оператора delete на объектах Windows, должно быть редко. Ниже приведены некоторые случаи, когда использование delete правильный выбор.
Автоматическая очистка с CWnd::PostNcDestroy
Когда система уничтожает окно Windows, последнее отправленное сообщение Windows в окно WM_NCDESTROY. Обработчик CWnd по умолчанию для данного сообщения CWnd::OnNcDestroy. OnNcDestroy окончательно удаляет HWND из объекта C++ вызывает виртуальная функция PostNcDestroy. Некоторые классы переопределяют этой функции для удаления объекта C C++.
Реализация по умолчанию CWnd::PostNcDestroy не выполняет никаких действий, которое подходит для объектов окна, выбранные в кадре стека или внедрены в другие объекты. Это не подходит для объектов окна, созданные для выделенным в куче без любых других объектов. Другими словами, не подходит для объектов окна, не внедряются в других объектах C C++.
Эти классы, созданные для выделенным отдельно в переопределении кучи метод PostNcDestroy для выполнения delete this. Это выписка освободит высвободившаяся память, связанной с объектом C C++. Даже если деструктор CWnd по умолчанию вызывает DestroyWindow при m_hWnd отличное от NULL, это не приводит к бесконечной рекурсии, поскольку дескриптор будет окончательно удален и NULL на этапе очистки.
Примечание
Система обычно вызывает CWnd::PostNcDestroy после того, как она процессы сообщение WM_NCDESTROY Windows и HWND и объект окна C++ больше не подключена.Система также вызывает CWnd::PostNcDestroy в реализации большинство вызовов CWnd::Create, если происходит сбой.Автоматические правила очистки описанные далее в этом разделе.
Автоматические классы очистки
Следующие классы не предназначены для очистки автоматически. Они, как правило, внедренных в других объектах C или C++ в стеке.
Все стандартные элементы управления Windows CStatic, CEdit, CListBox и т д).
Все дочерние окна производные непосредственно из CWnd (например пользовательских элементов управления).
Окна-разделители (CSplitterWnd).
Панели элементов управления по умолчанию (классов, производных от CControlBar см. в разделе Техническое примечание 31 для включения автоматического удаления объектов панели элементов управления).
Диалоговые окна (CDialog), предназначенных для модальных окон в кадре стека.
Все стандартные диалоговые окна, CFindReplaceDialog.
Диалоговые окна по умолчанию, созданные классы ClassWizard.
Следующие классы предназначены для очистки автоматически. Обычно установлены сами по себе в куче:
Основные фреймовые окна (производный прямо или косвенно от CFrameWnd).
Окна представления (производный прямо или косвенно от CView).
Если требуется прервать выполнение эти правила, необходимо переопределить метод PostNcDestroy в производном классе. Чтобы добавить автоматическая очистка к классу, вызовите свой базовый класс и выполните delete this. Чтобы удалить автоматическая очистка из класса, вызовите CWnd::PostNcDestroy напрямую вместо метода PostNcDestroy вашей прямой базовый класс.
Наиболее распространенным применением изменения автоматическое расширение функциональности очистки создание безрежимное диалоговое окно, в котором можно выбрать в куче.
Если вызвать удаление
Рекомендуется вызывать DestroyWindow для удаления объекта Windows, или метод C или 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 диагностические сообщит, что при освобождении памяти два раза. 2 Вхождения первого явно вызывать и косвенный вызов delete this в реализации автоматически очистки PostNcDestroy.
После вызова DestroyWindow объекта не-ПУСТО очистки объект C++, по-прежнему будет вращаться, но m_hWnd будет NULL. После вызова DestroyWindow объекта очистки, будет автоматически сохраняется объект C++ освобоженный оператора Delete C++ в реализации автоматически очистки PostNcDestroy.