Время жизни объекта;Существует ли термин / шаблон / что-то еще для следующей проблемы? - PullRequest
2 голосов
/ 20 июня 2011

Я пытаюсь написать класс обратного вызова для моих окон GUI. Чтобы (надеюсь) добиться этого, я использую делегатов.

typedef srutil::delegate2<void,DWORD,DWORD> CallbackMethod;
typedef std::map<MESSAGE_TYPE,std::vector<CallbackMethod>> CallbackMap;

MESSAGE_TYPE - это перечисление.

Мне нужен какой-то способ, который автоматически отменяет регистрацию любого объекта на карте, когда он разрушается, через некоторый постоянный / постоянный индекс, который не зависит от модификации деструктора класса.

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

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

Так что я думаю, что мне нужно что-то вроде самоосознающего индекса указателя константной ссылки.

Существуют ли такие вещи? Мне кажется, что это должно быть общей проблемой ...

1 Ответ

2 голосов
/ 20 июня 2011

Наверху, я угадаю ... нет, его не существует (по крайней мере, не для C ++).

Ваше предложение подразумевает сложную ситуацию (даже если выне использовал обратные вызовы).Вы просите что-то, что, по своему собственному уничтожению, позаботится об удалении любой ссылки о себе (потенциально) из любой структуры данных, которая ссылается на нее.Это довольно сложный заказ, и он не предназначен для STL.


Если вы действительно хотите это сделать (и я уверен, что вы это делаете), то вот мои первые мысли.Каждый раз, когда ваш объект добавляется в структуру данных, вы можете потребовать, чтобы структура данных была зарегистрирована в объекте, например, с помощью метода, подобного Object::Register(const std::vector<Object> &v).Затем вы можете сохранить ссылку (фактически, вы, вероятно, захватите указатель) на vector, так что вы можете сказать vector, чтобы удалить объект при уничтожении.Конечно, у этого есть две проблемы:

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

Так что, да, там особой помощи нет.


Лично у меня есть гораздо более предпочтительное решение, которое вращается вокруг событий (в частности, событие на основе делегата, например,что мы используем в c #).Если вы не знакомы с тем, как это работает, вы можете прочитать это руководство по программированию .С другой стороны, вы можете этого не делать, поскольку мы используем c ++, а не c #, и, поскольку я в значительной степени опишу это сам.

Одна из причин, по которой мне нравится идея события, заключается в том, что вы уже используете обратные вызовы.Делегаты (как в c # делегатах) являются просто расширением обратных вызовов.Они в основном инкапсулируют поведение vector<Callback> в классе Delegate.Класс Delegate позволяет вызывать все эти методы одной операцией, если вы перегружаете оператор вызова функции.Также, как и delegate, который вы уже используете, он, скорее всего, будет параметризованным типом.(На самом деле, когда C++0x все готово к работе, что скоро произойдет, вариационных шаблонов также будет весьма полезным).

Anyhoo, смысл всего этогов том, что вы могли бы иметь такую ​​Delegate переменную-член любого из ваших классов:

class Object
{
    public:
    ... // whatever constructors, etc. you might need
    Delegate<void, Collection, EventArgs> destroyHandler;
    ... // and number of event handlers can be used.
};

Теперь любой класс структуры данных может зарегистрировать обратный вызов, например:

obj.destroyHandler += myDelegate;

, где myDelegate - любая функция с необходимым типом.

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

Еще одна ошибка найдена в строке Delegate<void, Collection, EventArgs> destroyHandler;.Что означает каждый из этих параметров типа?Ну, void должно быть довольно ясно: это просто тип возврата методов.Кроме того, EventArgs просты: он просто переносит все данные, которые необходимо передать обратным вызовам.Тип Collection самый странный - зачем нам параметризировать используемую коллекцию типов?

Это обходить неловкость использования функций указателя на член в c ++.Хотя такие указатели возможны, их ужасно использовать, и (насколько мне известно) нет способа взять функции указателя на член из нескольких типов и сохранить их в одной коллекции.

Вместо этого, то, что я пробовал в прошлом (хотя я на самом деле не закончил идею), было что-то вроде

class MyVector
{

    static void DestructionHandler( MyVector & v, EventArgs & args )
    {
        // ... Handler code goes here
    }

};

Обратите внимание на параметр MyVector & v: он заменяет обычный this указательТакже обратите внимание, что метод static - это позволяет использовать его в качестве обычного старого указателя на функцию в стиле C.

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

...