Page 1 of 1

Наследование от wxEvtHandler , уничтож

Posted: Sun Nov 23, 2008 11:43 am
by m1t0z
Здравствуйте. Имеется необходимость создать класс, умеющий принимать сообщения( аля от wxPostEvent ). Самым логичным показалось унаследовать класс от wxEvtHandler. Таким образом последнее время и поступал, пока не начлася падёж на одном из таких классов. После продолжительных поисков причину нашел(кажется). Заключается она в том что при удалении объекта такого класса в очереди сообщений еще могут остаться к нему необработанные сообщения. Тоже самое, насколько я знаю, случается если удалять через delete объекты, унаследованные от wxWindow - посему в документации и рекомендуют настоятельно узать wxWindow::Destroy(), реализующий отложенное уничожение объекта.
Каким образом стоит поступать мне - перенаследовать все классы от wxWindow и узать Destroy или есть какой-то другой, способ( может отложенное удаление как то заложенно в сам класс wxEvtHandler ). Вариант с наследованием от wxWindow не очень симпатизирует - все таки не "окна" делаю.

Posted: Mon Nov 24, 2008 2:08 pm
by radcapricorn
в очереди сообщений еще могут остаться к нему необработанные сообщения.
Как это "к нему"? Падеж может быть, если например кто-то пытается вызвать метод по указателю на удаленный объект. Но при чем здесь очередь сообщений? Если я правильно понимаю, то это может возникать разве что из-за того, что объект был удален, но не изъят из списка обработчиков, в который он был помещен.

Можно пример использования такого класса для ясности?

Posted: Mon Nov 24, 2008 2:45 pm
by m1t0z
radcapricorn wrote: Если я правильно понимаю, то это может возникать разве что из-за того, что объект был удален, но не изъят из списка обработчиков, в который он был помещен.
Вообщем то это я имел ввиду
radcapricorn wrote: Можно пример использования такого класса для ясности?
Частный пример, на котором падеж:

Есть класс, унаследованный от wxEvtHandler. В нем агрегирован объект типа wxSocketBase *. У данного объекта я использую метод SetEventHandler, для того, чтобы отслеживать события, происходящие на сокете. Параметром в SetEventHandler передаю this.

Дальше наибольший интерес представляет деструктор класса:
в котором я вызываю Destroy для объекта сокета( + предварительно вызываю notify(false) для того же объекта сокета).

Если я не вызываю деструктор класса( не уничтожаю объект ) проблем никаких нет, а вот когда вызываю - случаются падежи.

Т.е. действительно подозрения на то, что мой объект не был изьят из списков обработчиков. Как это можно сделать?

Posted: Mon Nov 24, 2008 3:59 pm
by radcapricorn
В случае с wxSocketBase - никак, да это и не нужно. Скорее всего нужно убедиться в том, что объект-агрегат умрет после сокета.

Здесь возможен вариант, что события, сгенерированные сокетом до его удаления по Destroy(), еще будут доставляться (т.к. он "физически" умрет только в слующий idle time). Только вот сам обработчик к этому времени будет уже уничтожен.

В данном случае это чисто мое ИМХО, я просто бегло пробежался по исходникам wxWidgets. Так что могу заблуждаться :wink:

Случай действительно интересный. Падежи происходят в деструкторе или "случайно", но после вызова деструктора?

Posted: Mon Nov 24, 2008 4:24 pm
by m1t0z
radcapricorn wrote:Падежи происходят в деструкторе или "случайно", но после вызова деструктора?
В том то и дело, что случайно после вызова деструктора.

Posted: Mon Nov 24, 2008 4:29 pm
by m1t0z
radcapricorn wrote:В случае с wxSocketBase - никак, да это и не нужно. Скорее всего нужно убедиться в том, что объект-агрегат умрет после сокета.
Есть идеи как это реализовать, без наследования от wxSocketClient/wxSocketServer?

Posted: Mon Nov 24, 2008 4:35 pm
by radcapricorn
Судя по всему, так и есть - остается какая-то связка между сокетом и обработчиком, причем второй удаляется явно раньше первого.

Можно попробовать реализовать Destroy() для обработчика вот так:

Code: Select all

wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : 0;
if (traits)
{
    traits->ScheduleForDestroy(this);
}
else
{
    delete this;
}

Posted: Mon Nov 24, 2008 5:40 pm
by T-Rex
А елси wxTheApp->Yield() вызвать в деструкторе после Notify(false) и удалением сокета разве сообщения в очереди не обработаются?

Posted: Mon Nov 24, 2008 6:10 pm
by m1t0z
radcapricorn wrote:Судя по всему, так и есть - остается какая-то связка между сокетом и обработчиком, причем второй удаляется явно раньше первого.

Можно попробовать реализовать Destroy() для обработчика вот так:

Code: Select all

wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : 0;
if (traits)
{
    traits->ScheduleForDestroy(this);
}
else
{
    delete this;
}
Спасибо! Помогло )

p.s. В официальный мануалах описание wxAppTraits::ScheduleForDestroy() не нашел, только в хидерах библиотеки непосредственно. Много еще такого скрытого богатсва в wx?

Posted: Mon Nov 24, 2008 6:12 pm
by m1t0z
T-Rex wrote:А елси wxTheApp->Yield() вызвать в деструкторе после Notify(false) и удалением сокета разве сообщения в очереди не обработаются?
Как ни странно, но это не помогло...

Posted: Mon Nov 24, 2008 8:58 pm
by radcapricorn
m1t0z,
p.s. В официальный мануалах описание wxAppTraits::ScheduleForDestroy() не нашел, только в хидерах библиотеки непосредственно. Много еще такого скрытого богатсва в wx?
Да прилично, если в сырцах поковыряться :-)

T-Rex,

Насчет Yield() и почему оно не помогает - тут уж не знаю. Будет время - покопаюсь в исходниках "на пощупать".

Posted: Tue Jan 27, 2009 9:20 pm
by Billy Bones
Можно еще попробовать вызвать вполне себе документированный метод wxSocketBase::Close(). Он прибивает сообщения в очереди.

Posted: Fri Jan 30, 2009 1:01 pm
by radcapricorn
Оживляем тему? :-)

Code: Select all

wxSocketBase::Close
void Close()

(1) ...Upon socket destruction, Close is automatically called...

Remark/Warning

(2) Although Close immediately disables events for the socket, it is possible that event messages may be waiting in the application's event queue. The application must therefore be prepared to handle socket event messages even after calling Close.
Из (1) следует отсутствие необходимости явного вызова Close().

Из (2) - наличие уже назначенных (до вызова Close()) событий, которые никто вовсе и не прибивает.