共享的从属对象

时间:2018-09-19 15:04:56

标签: c++ c++11 templates

我有一个模板类Foo,它有一个方法barMethod,它需要一个Bar对象。我可以让每个Foo对象根据需要创建Bar对象,但是我不想这样做,因为它会很慢,而且很可能存在不同的Foo对象可以使用相同的Bar对象。

鉴于此,我想有一个BarManager对象,该对象具有一组现有的Bar对象。然后,Foo对象可以向其请求Bar对象,如果已经存在合适的对象,则管理器将简单地将其返回。如果没有,经理将创建一个新的并将其退回。

在我看来,实施“经理”方法存在两个问题。

  1. 管理器必须是一个全局变量,我不希望这样做。
  2. BarManagerBar都是模板类,因此即使我要使管理器成为全局变量/对象,也不确定如何工作。我想我可以将全局变量设置为void *,并在将其取消引用到适当的模板化类时将其强制转换,但这看起来确实很丑。

必须有一种不那么丑陋的方法(也许使用auto指针?)。什么事?

编辑:该软件是我(也许还有其他人)稍后将使用的库的一部分,这就是为什么对类进行模板化且模板类型未知的原因。另外,我想使Foo的用户的操作尽可能简单,因此我不希望调用者对BarManagerBar做任何事情(例如,实例化{{ 1}},并引用每个BarManager)。

3 个答案:

答案 0 :(得分:3)

如果您:

  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;
}

答案 1 :(得分:0)

关于如何引用BarManager的方法有两种:

  1. 将其作为全局对象/指向main() / singleton / monostate中局部对象的全局指针。优点是易于访问。
  2. 显式地将指针/引用传递给BarManager的实例。好处是您可以有许多BarManager对象。缺点是必须将额外的参数传递给调用,尤其是在调用链很深和/或必须将对其的引用/指针存储为成员变量的情况下。

答案 2 :(得分:0)

因此,您需要负责构造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); }
};