Войти
ПрограммированиеФорумОбщее

Кеш и врапперы и умные указатели(крестопроблемы)

#0
(Правка: 22:01) 21:59, 6 ноя. 2019

Есть простая проблема - обернуть враппером один класс, которая меня поставила в ступор, я даж накидал пример для простоты

Короче проще смотреть в код:

Ранее решение было простое вот оно:

struct some_object_params
{
  some_object_params() { std::cout << "some_object_params ctor" << std::endl; }
  ~some_object_params() { std::cout << "some_object_params dtor" << std::endl; }

  int param() const noexcept { return 4; }
};

struct some_object
{
  some_object() { std::cout << "some_object ctor" << std::endl; }
  ~some_object() { std::cout << "some_object dtor" << std::endl; }

  some_object_params const & params() const noexcept
  {
    return _params;
  }

private:
  some_object_params _params;
};

struct some_object_params_wrapper
{
  some_object_params_wrapper(std::shared_ptr<some_object> const & ptr) : _obj(ptr) {}

  int param() const noexcept { return _obj->params().param(); }
private:
  std::shared_ptr<some_object> _obj;
};

struct some_object_wrapper
{
  //extra memory allocation here
  some_object_wrapper() : _obj(std::make_shared<some_object>()) {}

  std::shared_ptr<some_object_params_wrapper> const & params() const noexcept
  {
    if (!_params_wrap_cache)
      _params_wrap_cache = std::make_shared<some_object_params_wrapper>(_obj);
    return _params_wrap_cache;
  }

private:
  std::shared_ptr<some_object> _obj;
  mutable std::shared_ptr<some_object_params_wrapper> _params_wrap_cache;
};

int main()
{
  auto obj_wrap = std::make_shared<some_object_wrapper>();
  return obj_wrap->params()->param();
}

Как мы видим тут есть одно очень неприятное выделение памяти, которое нафиг не нужно и можно some_object создавать прям в классе обёртки, но есть один нюанс..........

Если some_object_wrapper умирает, и кто-то до этого во внешнем коде оставил для себя shared_ptr<some_object_params_wrapper> - то очевидно мы не должны грохать some_object_wrapper, если мы в нём будем хранить some_object как простое поле, и тут начинается дичь - из-за того что оно ещё и кешированное!!

Попробуем конструктор владения

ВНИМАНИЕ !! Код с фундаментальными ошибками

struct some_object_params_wrapper
{
  some_object_params_wrapper(some_object const &  ref) : _obj(ref) {}

  int param() const noexcept { return _obj.params().param(); }
private:
  some_object const & _obj;
};

struct some_object_wrapper : public std::enable_shared_from_this<some_object_wrapper>
{
  std::shared_ptr<some_object_params_wrapper> const & params() const noexcept
  {
    if (!_params_wrap_cache)
      _params_wrap_cache = std::shared_ptr<some_object_params_wrapper>(shared_from_this(), new some_object_params_wrapper(_obj));
    return _params_wrap_cache;
  }

private:
  some_object _obj;
  mutable std::shared_ptr<some_object_params_wrapper> _params_wrap_cache;
};

Обычные подход с конструктором владения shared_ptr не катит - т.к.
1.  some_object_params_wrapper созданный через new никто не удалит, т.к. шаред владения не вызывает delete - утечка раз!
2.  из-за кеширования _params_wrap_cache - лишняя ссылка на some_object_wrapper будет всегда, т.к. её держит  std::shared_ptr<some_object_params_wrapper> - утечка два!

И вот я сижу выкурил уже пол пачки - и медитирую...... чтобы такого придумать.
А теперь задача:
  some_object_params_wrapper и some_object_wrapper (вернее их шареды) - это некое внешнее апи, которое отдаётся наверх

пользователь имеет право хранить shared_ptr<some_object_wrapper>, но может хранить и shared_ptr<some_object_params_wrapper>, а shared_ptr<some_object_wrapper> похерить, при этом при обращении к shared_ptr<some_object_params_wrapper> - должно остаться валидным. Избавится от кеширования не удастся т.к. обращение к params() - крайне частое, а сам some_object_params крайне тяжёлый - создавать и убивать каждый раз не вариант.

Собственно: Что посоветуют местные мудрецы?

ПС
Интересует именно лаконичное решение....костылные и уродливые решения(вплоть до рав поинтеров) ясен пень можно наговнякать 


#1
(Правка: 23:27) 22:24, 6 ноя. 2019

fsmoke
> some_object_params_wrapper созданный через new никто не удалит, т.к. шаред
> владения не вызывает delete - утечка раз!
В чём проблема держать some_object_params_wrapper как член класса, а в конструктор передавать просто указатель на него?

P.S.
Решение в shared_ptr:

+ Показать

#2
23:00, 6 ноя. 2019

maks242
> В чём проблема держать some_object_params_wrapper как член класса, а в
> конструктор передавать просто указатель на него?
Хммм... да завтра попробую - дело в том, что у меня не shared_ptr, а некие marshal обёртки интерфейсов с похожим поведением - здесь я упростил до shared_ptr'ов, не знаю удастся ли  избавится от new для наших убер механизмов - если получится, то таки да - это решение... пасиб

ПрограммированиеФорумОбщее