Trying to learn something new every day I'd be interested if the following is good or bad design.
I'm implementing a class A
that caches objects of itself in a static private member variable std::map<> cache
. The user of A
should only have access to pointers to elements in the map, because a full copy of A
is expensive and not needed. A new A
is only created if it is not yet available in the map, as construction of A
needs some heavy lifting. Ok, here's some code:
class B;
class A {
public:
static A* get_instance(const B & b, int x) {
int hash = A::hash(b,x);
map<int, A>::iterator found = cache.find(hash);
if(found == cache.end())
found = cache.insert(make_pair(hash, A(b,x))).first;
return &(found->second);
}
static int hash(B & b, int x) {
// unique hash function for combination of b and x
}
// ...
private:
A(B & b, int x) : _b(b), _x(x) {
// do some heavy computation, store plenty of results
// in private members
}
static map<int, A> cache;
B _b;
int _x; // added, so A::hash() makes sense (instead of B::hash())
// ...
};
Is there anything that is wrong with the code above? Are there any pitfalls, do I miss memory management problems or anything else?
Thank you for your feedback!
The implementation is intended to only allow you to create items via get_instance(). You should ideally make your copy-constructor and assignment operator private.
It would not be thread-safe. You can use the following instead:
Change the map to map
Have a mutex and use it thus:
Ideally only get_instance() will be static in your class. Everything else is private implementation detail and goes into the compilation unit of your class, including AControl.
Note that you could do this a lot simpler by just locking through the entire process of looking up in the map and creating but then you are locking for longer whilst you do the long construction process. As it is this implements record-level locking once you have inserted the item. A later thread may find the item uninitialised but the
boost::once
logic will ensure it is created exactly once.