1

我正在为一堆对象的延迟初始化创建一个类(不是完全通用的,都在我的控制之下)。每种类型只存在一个对象。我已经使用std::vectorand有一个线性时间实现boost::any。希望它可以更好地了解我在说什么。

我可以假设我想要访问的所有对象都有

typedef boost::shared_ptr<CLASSNAME> HandleType

在它们的定义中,它们都有一个构造函数,该构造函数通过引用获取 ObjectProvider。

class ObjectProvider {
    typedef std::vector<boost::any> ContainerType;
    ObjectProvider() : container() {}

public:

    // this is where the relevant method is
    template <class TElementType>
    typename TElementType::HandleType get() {
        for (ContainerType::iterator it = container.begin(); it != container.end(); ++it) {
            try {
                return boost::any_cast<typename TElementType::HandleType>(*it);
            } catch (boost::bad_any_cast &) {}
        }
        // failed to find it so create it
        TElementType::HandleType handle = boost::make_shared<TElementType>(*this);
        container.push_back(handle);
        return handle;            
    }

private:
    ContainerType container;
};


// ----- FOR TESTING -----
class SomeObject {
public:
     SomeObject(ObjectProvider &) {}
     typedef boost::shared_ptr<SomeObject> HandleType;
};

int main(int argc, char** argv) {
    ObjectProvider provider;

    // expensive creation is done here
    SomeObject::HandleType obj1 = provider.get<SomeObject>();

    // expensive creation is not re-done
    SomeObject::HandleType obj2 = provider.get<SomeObject>();
    assert (obj1 == obj2); // pointers should point to the same object

}

一些动机:其中许多对象(它们是各种服务的客户端)需要创建各种类型的附加客户端,但我不想每次都重新创建它们。所以这个类的目标是提供一种缓存已经创建的客户端的方法。

这是我的问题:

  • 有一个更好的方法吗?

  • 特别是,有没有办法避免循环输入get<...>()并以某种方式按类型键入?我希望有恒定时间访问而不是线性时间,并且当前方法无法利用可用于查找的类型信息。

只是为了对我的想法做一些额外的解释,我可能会在 Java 中做这样的事情:

Map<Class<?>, Object> objMap;
public <T> T get(Class<T> class) {
    Object obj = objMap.get(class);
    if (obj != null) {
        return (T)obj;
    } else {
        T newObj = ;// fiddle with java reflection to create a new instance
        objMap.put(class, newObj);
    }
 }
4

4 回答 4

1

如果每种类型只有一个,那么您可以使用typeid提取表示该类型的字符串,并将其用作 amap或的键unordered_map

    //...
    typedef std::map<std::string, boost::any> ContainerType;
    //...

    template <class TElementType>
    typename TElementType::HandleType get() {
        std::string name = typeid(TElementType).name();

        ContainerType::iterator it = container.find(name);
        if (it != container.end()) {
            try {
                return boost::any_cast<typename TElementType::HandleType>(it->second);
            } catch (boost::bad_any_cast &) {}
        }
        // failed to find it so create it
        TElementType::HandleType handle = boost::make_shared<TElementType>(*this);
        container[name] = handle;
        return handle;            
    }
于 2013-08-27T18:55:19.477 回答
0

如果您希望一个类只实例化一次,您可能正在寻找设计模式singleton

维基百科定义:

在软件工程中,单例模式是一种将类的实例化限制为一个对象的设计模式。当需要一个对象来协调整个系统的动作时,这很有用。这个概念有时被推广到当只有一个对象存在时运行效率更高的系统,或者将实例化限制为一定数量的对象。该术语来自单例的数学概念。

关于单例的其他链接

C++ 单例设计模式

单例:应该如何使用

任何人都可以为我提供 C++ 中的 Singleton 示例吗?

你可以在互联网上找到更多关于它的解释。

于 2013-08-27T18:54:06.397 回答
0

如果你担心 typeid() 支持,你也可以自己添加一个类索引。

class SomeObject {
public:
    SomeObject(ObjectProvider &) {}
    typedef boost::shared_ptr<SomeObject> HandleType;
    static const int ClassIndex = 0;
};

并且对象提供者变为

class ObjectProvider {
    typedef std::vector<boost::any> ContainerType;

public:
    ObjectProvider() : container() {}

    // this is where the relevant method is
    template <class TElementType>
    typename TElementType::HandleType get() {
        int idx = TElementType::ClassIndex;
        if (container.size() <= idx) {
            container.resize(idx + 1);
        }

        // Check if object exists
        if (container[idx].empty()) {
            typename TElementType::HandleType handle = boost::make_shared<TElementType>(*this);
            container[idx] = handle;
        }

        return boost::any_cast<typename TElementType::HandleType>(container[idx]);
    }

private:
    ContainerType container;
};

不利的一面是,您必须确保不同的类不会在 ClassIndex 字段上发生冲突。

于 2013-08-27T19:21:30.857 回答
0

如果您想要恒定时间访问,您可以创建自己的类型 ID:

class Registry
{
private:
    static int get_id()
    {
        static int id = 0;
        return id++;
    }

    template< typename T>
    static int get_type_id()
    {
        const static int id = get_id();
        return id;
    }
    std::vector<HandleType> handles;
    HandleType make_handle( const Registry&r)
    {
        // do what you need to do to create a new handle.
    }
public:
    template<typename T>
    HandleType get()
    {
        int id = get_type_id<T>();
        if (id + 1 > handles.size())        
        {
            handles.resize( id + 1, HandleType());
        }
        if (!handles[id])
        {
            handles[id] = make_handle( *this);
        }
        return handles[id];
    }

};

编辑:我看到我基本上给出了与 umlum 相同的答案,除了这个答案还尝试为每种类型自动创建一个数字 id。

于 2013-08-27T19:28:22.740 回答