I have an application that has several objects (about 50 so far, but growing). There is only one instance of each of these objects in the app and these instances get shared
Yes, there is a way. A pretty simple even in C++ to what that C# code does (without checking for inheritance though):
template
BrokeredObject * GetOrCreateObject() {
return new T();
}
This will work and do the same as the C# code. It is also type-safe: If the type you pass is not inherited from BrokeredObject (or isn't that type itself), then the compiler moans at the return statement. It will however always return a new object.
As another guy suggested (credits to him), this all looks very much like a fine case for the singleton pattern. Just do TypeA::getInstance() to get the one and single instance stored in a static variable of that class. I suppose that would be far easier than the above way, without the need for IDs to solve it (i previously showed a way using templates to store IDs in this answer, but i found it effectively is just what a singleton is).
I've read that you will leave the chance open to have multiple instances of the classes. One way to do that is to have a Mingleton (i made up that word :))
enum MingletonKind {
SINGLETON,
MULTITON
};
// Singleton
template
struct Mingleton {
static boost::shared_ptr getOrCreate() {
static D d;
return boost::shared_ptr(&d, NoopDel());
}
struct NoopDel {
void operator()(D const*) const { /* do nothing */ }
};
};
// Multiton
template
struct Mingleton {
static boost::shared_ptr getOrCreate() {
return boost::shared_ptr(new D);
}
};
class ImASingle : public Mingleton {
public:
void testCall() { }
// Indeed, we have to have a private constructor to prevent
// others to create instances of us.
private:
ImASingle() { /* ... */ }
friend class Mingleton;
};
class ImAMulti : public Mingleton {
public:
void testCall() { }
// ...
};
int main() {
// both do what we expect.
ImAMulti::getOrCreate()->testCall();
ImASingle::getOrCreate()->testCall();
}
Now, you just use SomeClass::getOrCreate() and it cares about the details. The custom deleter in the singleton case for shared_ptr makes deletion a no-op, because the object owned by the shared_ptr is allocated statically. However, be aware of problems of destruction order of static variables: Static initialization order fiasco