Я встретил интересную проблему при реализации шаблона Observer с С++ и 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" и все итераторы, которые я использую. Решение довольно простое - я делаю снимок зарегистрированного списка наблюдателей и перебираю снимок. Добавление новых наблюдателей не отменяет моментальный снимок, поэтому все выглядит нормально. Но здесь возникает другая проблема: наблюдатели решают уничтожить себя при уведомлении. Хуже того, один наблюдатель может решить уничтожить всех других наблюдателей (они контролируются из сценариев), что делает недействительными как очередь, так и моментальный снимок. Я нахожусь итерацией по выделенным указателям.
Мой вопрос: как я должен справляться с ситуациями, когда наблюдатели убивают друг друга? Есть ли готовые к использованию шаблоны? Я всегда думал, что "Observer" - самый простой шаблон дизайна в мире, но теперь кажется, что его не так просто реализовать правильно...
Спасибо, всем за ваш интерес. Давайте получим сводку решений:
[1] "Не делай этого" Извините, но это обязательно. Наблюдатели контролируются из сценариев и собираются с мусором. Я не могу контролировать сбор мусора, чтобы предотвратить их выделение,
[2] "Использовать boost:: signal" Самое многообещающее решение, но я не могу повысить эффективность проекта, такие решения должны принимать только руководитель проекта (мы пишем в Playstation );
[3] "Использовать shared__ptr" . Это предотвратит выделение наблюдателей. Некоторые подсистемы могут полагаться на очистку пула памяти, поэтому я не думаю, что могу использовать shared_ptr.
[4] "Отложить освобождение наблюдателя" Наблюдатели очереди для удаления при уведомлении, затем используйте второй цикл для их удаления. К сожалению, я не могу предотвратить освобождение, поэтому я использую трюк оберточного наблюдателя с каким-то "адаптером", сохраняя фактически список "адаптеров". На деструкторе наблюдатели отменяют свои адаптеры, затем я беру свой второй цикл, чтобы уничтожить пустые адаптеры.
p.s. это нормально, что я редактирую свой вопрос, чтобы подвести итог всему сообщению? Я ноб на StackOverflow...