Я столкнулся с интересной проблемой при реализации шаблона Observer с C ++ и STL. Рассмотрим этот классический пример:
class Observer {
public:
virtual void notify() = 0;
};
class Subject {
public:
void addObserver( Observer* );
void remObserver( Observer* );
private:
void notifyAll();
};
void Subject::notifyAll() {
for (all registered observers) { observer->notify(); }
}
Этот пример можно найти в каждой книге по шаблонам проектирования. К сожалению, реальные системы более сложны, поэтому возникает первая проблема: некоторые наблюдатели принимают решение добавить других наблюдателей в Субъект после получения уведомления. Это делает недействительным цикл for и все итераторы, которые я использую. Решение довольно простое - я делаю снимок списка зарегистрированных наблюдателей и перебираю снимок. Добавление новых наблюдателей не делает снимок недействительным, поэтому все выглядит хорошо. Но тут возникает другая проблема: наблюдатели решают уничтожить себя, получив уведомление. Хуже того, один наблюдатель может решить уничтожить всех остальных наблюдателей (они управляются из сценариев), и это делает недействительной очередь и снимок. Я ловлю себя на переборе нераспределенных указателей.
Мой вопрос: как мне справляться с ситуациями, когда наблюдатели убивают друг друга? Есть ли готовые шаблоны? Я всегда думал, что «Обозреватель» - это самый простой шаблон проектирования в мире, но сейчас кажется, что его не так просто реализовать правильно ...
Спасибо всем за проявленный интерес. Позвольте нам иметь резюме решений:
[1] «Не делай этого» * 1013 * Извините, но это необходимо. Наблюдатели управляются из сценариев и собирают мусор. Я не могу контролировать сборку мусора, чтобы предотвратить их удаление;
[2] «Использовать надстройку :: сигнал» Самое многообещающее решение, но я не могу дать надежду проекту, такие решения должны приниматься только руководителем проекта (мы пишем в Playstation) ;
[3] «Использовать shared__ptr» Это предотвратит перераспределение наблюдателей. Некоторые подсистемы могут полагаться на очистку пула памяти, поэтому я не думаю, что могу использовать shared_ptr.
[4] «Отложить освобождение наблюдателя» Поставить в очередь наблюдателей для удаления во время уведомления, а затем использовать второй цикл для их удаления. К сожалению, я не могу предотвратить освобождение, поэтому я использую хитрость обертывания наблюдателя с каким-то «адаптером», сохраняя фактически список «адаптеров». На деструкторе наблюдатели отменяют назначение со своих адаптеров, затем я беру второй цикл, чтобы уничтожить пустые адаптеры.
p.s. это нормально, что я редактирую свой вопрос, чтобы подвести итог всего поста? Я нуб на StackOverflow ...