Re[30]: Исповедь C++ника
От: so5team https://stiffstream.com
Дата: 27.12.20 22:16
Оценка:
Здравствуйте, 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-е здесь не видно, но сам по себе код с такими кастами попахивает.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.