I'm making a class for lazy initialization of a bunch of objects (not totally generic, all under my control). Only one object of each type will exist. I have a linear-time implementation using std::vector
and boost::any
already. Hopefully it should give a better idea of what I'm talking about.
I can make the assumption that all the objects I'll want to access have
typedef boost::shared_ptr<CLASSNAME> HandleType
in their definitions and they all have a constructor that takes the ObjectProvider by reference.
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
}
Some motivation: Many of these objects (they're clients for various services) require creating additional clients of various types, but I don't want to be recreating them each time. So the goal of this class is to provide a method of caching the already-created clients.
Here is my question:
Is there a better way to do this?
In particular, is there a way to avoid the loop in
get<...>()
and somehow key by type? I'd love to have constant-time access instead of linear time and the current method fails to make use of the type information available for lookup.
Just for a little additional explanation of what I'm thinking, I might do something like this in 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);
}
}