01 августа 2006

Убей родителя, и он убъет тебя

В ATL/WTL конструкция delete this; - дело довольно обычное. Так можно в OnFinalMessage() удалить собственный объект.

А теперь представьте ситуацию: WTL-контролы (кнопки, edit box-ы и т.п.) хранятся в контейнере указателей у их Parent-а (диалога, etc.). В своем OnFinalMessage() родитель делает delete this, а его деструктор грохает все объекты WTL-контролов.

Все хорошо до тех пор, пока мы не захотим по нажатию кнопки мыши на контроле закрыть окно родителя. В обработчике контрола по WM_LBUTTONDOWN (скажем, в CControl::OnLButton()) мы вызываем Parent->DestroyWindow() и... падаем по assert-у, так как parent удаляет наш объект, а мы еще не вышли из CControl::OnLButton(), и наш объект еще может понадобится (не в OnLButton(), а в вызвавшем его коде).

Можно, конечно, сделать PostMessage(Parent, WM_CLOSE или WM_DESTROY), и тогда родитель будет удален уже потом, после выхода из CControl::OnLButton(), так как WM_DESTROY дойдет до него не сразу, а просто встанет в очередь. Но иногда нужно грохнуть родителя здесь и сейчас.

Выход из такой ситуации: удалять свой объект должен сам контрол в своем OnFinalMessage(). Правда, родителю не помешает "подчищать" за своими детьми - если контрол был создан как объект, но не успел создасться как окно (в терминах WinAPI) - мало ли по каким причинам - то убить объект контрола должен родитель.

Комментариев нет: