我正在为一堆对象的懒惰初始化创建一个类(不是完全通用的,都在我的控制之下)。每种类型只有一个对象存在。我已经使用std::vector
和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);
}
}
答案 0 :(得分:1)
如果每种类型只有一种,那么您可以使用typeid
提取表示该类型的字符串,并将其用作map
或unordered_map
的键。 / p>
//...
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;
}
答案 1 :(得分:0)
如果您希望课程仅实例一次,您可能正在寻找设计模式 singleton 。
在软件工程中,单例模式是一种设计模式,它将类的实例化限制为一个对象。当需要一个对象来协调整个系统的操作时,这非常有用。该概念有时被推广到当仅存在一个对象时更有效地操作的系统,或者将实例化限制为特定数量的对象的系统。该术语来自单身人士的数学概念。
Singleton: How should it be used
Can any one provide me a sample of Singleton in c++?
你可以在互联网上找到更多关于它的解释。
答案 2 :(得分: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字段上发生冲突。
答案 3 :(得分:0)
如果您想要持续时间访问,可以创建自己的type-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。