Удаление объекта, который вы слушаете? - PullRequest
0 голосов
/ 19 марта 2011

Вот моя проблема:

Я создаю игровой графический интерфейс API.У него есть слушатель мыши.Допустим, слушателю мыши дано указание удалить любой виджет, который он слушает.Проблема заключается в том, что при удалении итератор уничтожается, поэтому он падает:

for(std::vector<AguiMouseListener*>::iterator it 
        = mouseListeners.begin(); it != mouseListeners.end(); ++it)
    {

        switch (event)
        {
        case AguiMouseEventArgs::AGUI_MOUSE_DOWN:
            (*it)->mouseDownCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_UP:
            (*it)->mouseUpCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_MOVE:
            (*it)->mouseMoveCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_CLICK:
            (*it)->mouseClickCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_DOUBLE_CLICK:
            (*it)->mouseDoubleClickCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_WHEEL_UP:
            (*it)->mouseWheelUpCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_WHEEL_DOWN:
            (*it)->mouseWheelDownCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_ENTER:
            (*it)->mouseEnterCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_LEAVE:
            (*it)->mouseLeaveCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_HOVER:
            (*it)->mouseHoverCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_DRAG:
            (*it)->mouseDragCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_MODAL_DOWN:
            (*it)->mouseModalDownCallback(mArgs);
            break;
        default:
            break;
        }
    }

Существует ли правильный способ для другого объекта удалить то, что он прослушивает, из обратного вызова?

Спасибо

class BillButton : public AguiMouseListener {
public:
    void mouseLeaveCallback(AguiMouseEventArgs &mouseArgs)
    {
        delete mouseArgs.getSourceWidget();
    }

};

Ответы [ 3 ]

1 голос
/ 19 марта 2011
  • Вы можете использовать std :: list вместо std :: vector. Когда вы удаляете из него элементы, вы не будете делать недействительными итераторы , поэтому вы можете продолжать цикл

  • Вы можете создать вектор / список объектов, которые должныбыть удаленным после завершения цикла.После завершения цикла переберите новую коллекцию, удалите их и удалите из исходного вектора.Новая коллекция может иметь тип указатель-на-указатель, поэтому вы не можете уничтожить ее во время итерации по ней

  • Вы можете добавить возвращаемое значение из вашего обратного вызова, которое учитывает некоторый потокконтроль.Например, как обработчики событий Win32 и WinForms устанавливают флаг wasHandled.В вашем случае вы бы сказали циклу обработчика, хотите ли вы прекратить (а также любой другой элемент управления потоком, который звучит интересно / полезно)

  • Вы можете реорганизовать свой код, чтобы использовать ссылкусчитая умные указатели для автоматического удаления, когда больше нет слушателей (или других вещей, ссылающихся на ваш объект).

Для решения с умным указателем один такой класс - std:: shared_ptr .Вы можете найти это в совершенно новых компиляторах (это может быть еще не стандартно, но это будет скоро), или в библиотеке Boost Smart Pointers .

0 голосов
/ 19 марта 2011

Вы не хотите удалять объекты, которые все еще могут обрабатывать события (особенно событие, которое обрабатывается в настоящее время).Иерархия представлений может обидно переплетаться.

Ваш обработчик не должен сам удалять, а регистрировать другое событие с родительскими объектами для фактического удаления, а затем возвращаться нормально (вы можете установить поле для объекта, которыйговорит игнорировать другие события, поэтому больше не обрабатывает).

Когда родитель получает событие удаления, он удаляет объект, который планируется удалить.

Я свободно использую термин родительский каклюбой объект выше в иерархии представления вплоть до оконного менеджера.

0 голосов
/ 19 марта 2011

Я бы предложил вернуть логическое значение из ваших обратных вызовов, указывающее, что обратный вызов использовал событие. Когда возвращается значение true, обратный цикл зацикливается. Это полезно в других ситуациях, кроме удаления владельца обратного вызова.

Кроме того, будьте осторожны, чтобы не получить доступ к состоянию виджета после вызова обратного вызова. При необходимости сделайте копии необходимых переменных состояния.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...