Общий подчиненный объект - PullRequest
       1

Общий подчиненный объект

0 голосов
/ 19 сентября 2018

У меня есть шаблон класса Foo, у которого есть метод barMethod, для которого требуется объект Bar.Я мог бы заставить каждый отдельный Foo объект создавать Bar объекты по мере необходимости, но я не хочу этого делать, потому что это будет медленно, и есть большая вероятность, что разные Foo объекты могут использовать один и тот же Bar object.

Учитывая это, я хотел бы иметь объект BarManager, который имеет существующий набор объектов Bar.Объекты Foo могут затем запросить у него объекты Bar, и если соответствующий объект уже существует, менеджер просто вернет его.Если этого не произойдет, менеджер создаст новый и вернет его.

Мне кажется, что есть две проблемы с реализацией подхода "менеджер".

  1. Менеджердолжна быть глобальная переменная, которую я предпочел бы не делать.
  2. BarManager и Bar оба являются шаблонными классами, поэтому даже если бы я сделал менеджер глобальной переменной / объектом, яЯ не уверен, как это будет работать.Я думаю, я мог бы сделать глобальную переменную void * и приводить ее всякий раз, когда она разыменовывается к соответствующему шаблонному классу, но это кажется действительно уродливым.

Должен быть способ сделать этоэто не так страшно (возможно, с помощью указателя auto?).Что это?

РЕДАКТИРОВАТЬ: Это программное обеспечение является частью библиотеки, которую я (и, возможно, другие) буду использовать позже, поэтому классы являются шаблонными, а тип шаблона неизвестен a priori .Кроме того, я хочу, чтобы пользователь Foo делал все как можно более простым, поэтому я не хочу, чтобы вызывающий оператор должен был что-либо делать с BarManager или Bar (например, создание экземпляра BarManager и указание ссылки накаждый Foo).

Ответы [ 3 ]

0 голосов
/ 19 сентября 2018

Таким образом, вам понадобилось бы то, что отвечало за построение Foo с, чтобы сначала сконструировать все BarManager с, а затем передать их в Foo при построении.Поскольку я на самом деле не знаю специфики, мне придется оставить это вам, но с учетом простого: template<typename T> struct Bar { using value_type = T; const T _val; }; ваш BarManager скелет может выглядеть так:

template<typename T>
class BarManager {
    vector<shared_ptr<Bar<T>>> _bars;
public:
    using value_type = T;
    size_t size() { size(_bars); }
    shared_ptr<Bar<T>>& get_bar(const T target) {
        const auto it = find_if(begin(_bars), end(_bars), [&](const shared_ptr<Bar<T>>& i) { return i->_val == target; });

        if(it == end(_bars)) {
            _bars.push_back(make_shared<Bar<T>>(target));
            return _bars.back();
        } else {
            return *it;
        }
    }
};

Оттуда ваш Foo может выглядеть так:

template<typename T>
class Foo {
    shared_ptr<BarManager<T>> _my_manager;
    shared_ptr<Bar<T>> _my_bar;
public:
    using value_type = T;
    Foo(shared_ptr<BarManager<T>>& my_manager) : _my_manager(my_manager) {}
    void request_bar(const T& target) { _my_bar = _my_manager->get_bar(target); }
};
0 голосов
/ 19 сентября 2018

Если вы:

  1. Знаете конкретный тип BarManager во время компиляции.
  2. Не хотите, чтобы любой пользователь Foo знал об этом внутреннем механизме.

Тогда все классы Foo могут содержать BarManager как static (определенно, не глобальную переменную)

template <typename T>
class Bar{};

template <typename T>
class BarManager;

template <typename T>
class Foo
{
private:
    static BarManager<T>& GetBarManager()
    {
        static BarManager<T> managerInstance;
        return managerInstance;
    }

public:
    void barMethod()
    {
        auto& bar = GetBarManager().GetBarInstance();

        // Do something with `bar`
    }
};

template <typename T>
class BarManager
{
public:
    Bar<T>& GetBarInstance()
    {
        // Replace with cacher implementation:
        static Bar<T> dud;
        return dud; 
    }
};

int main()
{
    Foo<int> foo;
    foo.barMethod();

    return 0;
}
0 голосов
/ 19 сентября 2018

Существует два варианта того, как ссылаться на BarManager:

  1. Имейте это как глобальный объект / глобальный указатель на локальный объект в main() / singleton / monostate.Преимущество - легкий доступ к нему.
  2. Передача указателя / ссылки на экземпляр BarManager в явном виде.Преимущество состоит в том, что вы можете иметь много BarManager объектов.Недостатком является необходимость передачи дополнительного параметра в вызовы, особенно если цепочки вызовов являются глубокими и / или необходимость сохранять ссылку / указатель на него как переменную-член.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...