Вынуждая что-то уничтожить последним в C ++ - PullRequest
6 голосов
/ 13 ноября 2008

Я работаю над приложением C ++, в котором есть некоторые объекты контроллера, которые регулярно создаются и уничтожаются (используя new). Необходимо, чтобы эти контроллеры зарегистрировались в другом объекте (назовем его controllerSupervisor) и отменили регистрацию при разрушении.

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

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

Будем благодарны за любые подсказки / предложения о возможных вариантах.

Ответы [ 15 ]

0 голосов
/ 14 ноября 2008

Как насчет того, чтобы супервайзер позаботился о разрушении контроллеров?

0 голосов
/ 14 ноября 2008

Сделайте инспектора Котрола синглтоном. Убедитесь, что конструктор элемента управления получает супервизор во время конструирования (не после слов). Это гарантирует, что супервизор управления полностью построен перед управлением. Таким образом, деструктор будет вызван перед деструктором супервизора управления.

class CS
{
    public:
        static CS& getInstance()
        {
            static CS  instance;
            return instance;
        }
        void doregister(C const&);
        void unregister(C const&);
    private:
        CS()
        {  // initialised
        }
        CS(CS const&);              // DO NOT IMPLEMENT
        void operator=(CS const&);  // DO NOT IMPLEMENT
 };

 class C
 {
      public:
          C()
          {
              CS::getInstance().doregister(*this);
          }
          ~C()
          {
              CS::getInstance().unregister(*this);
          }
 };
0 голосов
/ 14 ноября 2008

Это не совсем элегантно, но вы могли бы сделать что-то вроде этого:

struct ControllerCoordinator {
    Supervisor supervisor;
    set<Controller *> controllers;

    ~ControllerDeallocator() {
        set<Controller *>::iterator i;
        for (i = controllers.begin(); i != controllers.end(); ++i) {
            delete *i;
        }
    }
}

Новый глобальный:

ControllerCoordinator control;

Везде, где вы строите контроллер, добавляйте control.supervisor.insert(controller). Куда бы вы ни уничтожили, добавьте control.erase(controller). Вы можете избежать префикса control., добавив глобальную ссылку на control.supervisor.

Член-координатор координатора не будет уничтожен до тех пор, пока не будет запущен деструктор, так что вы гарантировано, что супервизор переживет контроллеры.

0 голосов
/ 13 ноября 2008

Вы можете посмотреть на использование количества зарегистрированных контроллеров в качестве дозорного для фактического удаления.

В этом случае вызов на удаление - это просто запрос, и вам нужно дождаться отмены регистрации контроллеров.

Как уже упоминалось, это одно из применений модели наблюдателя.

class Supervisor {
public:
    Supervisor() : inDeleteMode_(false) {}

    void deleteWhenDone() {
        inDeleteMode_ = true;
        if( controllers_.empty()){
            delete this;
        }
    }

    void deregister(Controller* controller) {
        controllers_.erase(
            remove(controllers_.begin(), 
                        controllers_.end(), 
                        controller));
        if( inDeleteMode_ && controllers_.empty()){
            delete this;
        }
    }


private:

    ~Supervisor() {}
    bool inDeleteMode_;
    vector<Controllers*> controllers_;
};

Supervisor* supervisor = Supervisor();
...
supervisor->deleteWhenDone();
0 голосов
/ 13 ноября 2008

Вы можете выполнить любое из следующих действий в зависимости от обстоятельств.

  1. Используйте шаблон Observer, предложенный Гурином. Обычно супервизор сообщает контролерам, что он отключается ...
  2. Пусть Супервайзер "владеет" контроллерами и будет нести ответственность за их уничтожение в случае его отказа.
  3. Храните контроллеры в shared_pointers, чтобы тот, кто выйдет из строя последним, совершит настоящее уничтожение.
  4. Управление (интеллектуальными указателями) контроллерами и супервизором в стеке, что позволит вам определить порядок уничтожения
  5. другие ...
...