Здравствуйте, so5team, Вы писали:
S>По поводу "мутно", если вам не понятно, то речь шла про понятность политки владения сущностями в вашем подходе. В C++ сборщика мусора нет. Возвращать голые владеющие указатели так себе способ.
Похоже, для того, чтобы разрешить должным образом проблемы владения (т.е. чтобы было безразлично, что именно удаляется первым -- тот, кто делает подписки или же сам SubscriptionStorage) нужно использовать что-то вроде:
template<class T>
class SubscriptionStorage {
public:
struct Subscription {
virtual ~Subscription() = default;
};
using SubscriptionHandle = std::unique_ptr<Subscription>;
[[nodiscard]]
SubscriptionHandle subscribe(T && value);
... // Конструктор и прочий фарш не показаны.
private:
struct Link {
virtual ~Link() = default;
Link * prev_;
Link * next_;
};
struct Internals : public std::enable_shared_from_this<Internals> {
Link sentinel_;
};
using InternalsShptr = std::shared_ptr<Internals>;
struct OneSubscription : public Link, public Subscription {
InternalsShptr internals_;
T value_;
OneSubscription(InternalsShptr internals, T && value)
: internals_{std::move(internals)}, value_{std::move(value)}
{}
~OneSubscription() override {
... // Вычеркивание себя из списка.
}
};
InternalsShptr internals_;
...
};
template<typename T>
SubscriptionStorage<T>::SubscriptionHandle SubscriptionStorage<T>::subscribe(T && value) {
auto result = std::make_shared<Subscription>(internals, std::move(value));
... // Провязывание новой подписки в список.
return result;
}
Вот в этом случае, КМК, не будет проблем с временами жизни. Пока живет хотя бы одна подписка, остается живым объект SubscriptionStorage::Internals. Следовательно, деструкторы Subscription могут спокойно вычеркивать себя из списка подписок даже если сам объект SubscriptionStorage прекратил свое существование. С другой стороны, если все объекты Subscription разрушаются до того, как умрет SubscriptionStorage, то вообще никаких проблем: ссылка на SubscriptionStorage::Internals останется только у SubscriptionStorage и этот Internals умрет сразу вслед за SubscriptionStorage.
Для уничтожения подписки достаточно просто "потерять" SubscriptionHandle. Или явно вызвать для него reset.
С другой строны, если SubscriptionHandle нигде не сохранить, то подписка исчезнет сразу же после создания.
Ну и в рамках C++98, где не было возможности создавать Movable+NonCopyable классы, пришлось бы, скорее всего, делать SubscriptionHandle в виде аналога shared_ptr.
Еще в этом подходе коряво то, что при движении по списку подписок нужно будет делать либо dynamic_cast от Link-а к OneSubscription, либо вообще, если RTTI под запретом, пользоваться reinterpret_cast-ом (вроде бы static_cast здесь не прокатит). В общем-то, опасности в reinterpret_cast-е здесь не видно, но сам по себе код с такими кастами попахивает.