Templates and lazy initialization - c++

I have a UIManager that manages a series of classes that inherit from a single UI class. Currently, it works something like this, where the individual UIs are initialized lazily and are stored statically:
class UIManager
{
public:
UIManager(); // Constructor
virtual ~UIManager(); // Destructor
template <typename T>
T *getUI()
{
static T ui(); // Constructs T, stores result in ui when
// getUI<T>() is first called
return &ui;
}
}
Called with:
getUI<NameEntryUI>()->activate();
or
getUI<MenuUI>()->render();
I am considering a design change that would allow me to have more than one player, hence more than one game window, hence more than one UIManager. I want all my constructed ui objects to be cleaned up when the UIManager is deleted (currently, because the ui objects are static, they stick around until the program exits).
How can I rewrite the above to remove the ui objects when UIManager is killed?
======================================
Here is the solution I've implemented. Early results are that it is working well.
Basically, I started with the idea suggested by Potatoswatter, which I liked because it was similar to an approach I had started then aborted because I didn't know about typeid(T). I backported the code to use only C++98 features. The key to the whole thing is typeid(T), which lets you map instantiated interfaces to their type in a consistent manner.
class UIManager
{
typedef map<const char *, UserInterface *> UiMapType;
typedef UiMapType::iterator UiIterator;
map<const char *, UserInterface *> mUis;
public:
UIManager(); // Constructor
virtual ~UIManager() // Destructor
{
// Clear out mUis
for(UiIterator it = mUis.begin(); it != mUis.end(); it++)
delete it->second;
mUis.clear();
}
template <typename T>
T *getUI()
{
static const char *type = typeid(T).name();
T *ui = static_cast<T *>(mUis[type]);
if(!ui)
ui = new T();
mUis[type] = ui;
return ui;
}
}

Currently, you only have storage space allocated for one UI element of each type. It's fundamentally impossible to keep that principle yet have any number of windows.
The quick and dirty solution would be to add a template argument for the window number. If it's a game, and you only have a limited number of players, you can have static storage for some predetermined number of windows.
template <typename T, int N>
T *getUI()
The approach of tying UI identity to the type system is fundamentally flawed, though, and I would recommend a more conventional approach using polymorphism and containers.
One way to identify the objects by type, yet store them dynamically, could look like
class UIManager {
std::map< std::type_index, std::unique_ptr< UIBase > > elements;
template< typename T >
T & GetUI() { // Return reference because null is not an option.
auto & p = elements[ typeid( T ) ];
if ( ! p ) p.reset( new T );
return dynamic_cast< T & >( * p );
}
}
Note that this requires UIBase to have a virtual destructor, or the objects won't be terminated properly when you quit.

Since you clearly need multiple objects per type, let's simply store the objects in a std::map<UIManager const*, T>. To pull out a specific managed object, it is looked up in the map for the corresponding type. The tricky bit is later getting rid of the objects which is handled using a list of function objects:
class UIManager
{
std::vector<std::function<void()>> d_cleaners;
UIManager(UIManager const&) = delete;
void operator=(UIManager const&) = delete;
public:
UIManager();
~UIManager();
template <typename T>
T *getUI() {
static std::map<UIManager const*, T> uis;
typename std::map<UIManager const*, T>::iterator it = uis.find(this);
if (it == uis.end()) {
it = uis.insert(std::make_pair(this, T())).first;
this->d_cleaner.push_back([it, &uis](){ uis.erase(it); });
}
return &(it->second);
}
};
The respective getUI() function stores a map mapping the address of the UIManager, i.e., this, to the corresponding object. If there is no such mapping, a new mapping is inserted. In addition, to make sure objects are cleaned up, a cleaner function is registered with this, simply erase() in the iterator just obtained from the corresponding map. The code is untested but something along those lines should work.

Related

Call a vector's function given the vector's pointer as a void *

I am working on implementing a game engine using ECS principles as an excercise. My current design has a ComponentManager class that is to store all the vectors that correspond to each component type. A minimal version of the class looks like this:
class ComponentManager{
private:
std::vector<void*> componentHolder;
public:
bool destroyEntity(int entityID, componentSignature toDestroy);
template <class T>
int registerComponent();
template <class T>
bool addComponent(int entity, T initialComp);
template <class T>
bool removeComponent(int entity);
};
The componentHolder is a vector of void* where each entry is the vector containing a different component type. The reason I am doing this is because I want to store all the components in contiguous memory, however each component is a different type. If I was to use a vector of pointers to some base component class, that would defeat the cache coherence, data-flow oriented benefits that I am trying to exploit with this ECS engine.
Also, My engine is designed so that others can create custom components by simply defining a struct containing the data they wish that component to store and registering that component on the creation of a new game "world" (or instance if you prefer). This registration is done via the registerComponent() function seen above, creating a unique id for each component type, and is defined as:
template <class T>
int ComponentManager::registerComponent(){
componentHolder.push_back(new std::vector<T>);
return type_id<T>();
}
The type_id() function is a trick I found from this stackexchange question and is what allows me to map the component types to integers which I use as indices in the ComponentManager vector. This has worked well for the creation/access of components, as those functions are templates and get the type of the component passed in (and as a result I can static cast the void* that is at the index of the componentHolder vector to the right type), here's an example of this:
template <class T>
bool ComponentManager::addComponent(int entityID){
int compID = type_id<T>();
std::vector<T>* allComponents = (std::vector<T>*)componentHolder[compID];
if (compEntityID.find(entityID) == compEntityID.end()){
(*allComponents).push_back(T());
return true;
}
return false;
}
however the issue comes from when I want to destroy an entity entirely. My function for destroying an entity simply requires the entity ID, and the component signature (a bitset that has bits flipped to 1 corresponding to which components this entity has) which is stored in the gameWorld object and is passed in. However, since the destroyEntity function does not get types passed into it via template functions, and only has the bitset to know which type of component to destroy, I can't figure out a way to get the type so that I can cast the void* to the right vector. Here is an example of what I want the destroyEntity function to do:
bool ComponentManager::destroyEntity(int entityID, componentSignature toDestroy){
for (int x = 0; x < MAX_COMPONENT; x++){
if (toDestroy[x]){
std::vector<??>* allComponents = (std::vector<??>*)componentHolder[x]; // Here is where the issue lies
(*allComponents).erase((*allComponents).begin() + entityIndex);
}
}
}
Is there a way during component registration for example that I could store a function pointer to each vector's erase method that I could later call from the destroyEntity() function? Or some way to store a map from the integer componentID I create during registration to the type itself, and use that later to cast? The types of components that are in the game will be known at run time, so I feel like this should be doable somehow? Also as a caveat there is some additional logic I have to figure out which entity owns which component in each component vector in componentHolder that I omitted for brevity, so that won't be causing any issues.
Thank you in advanced for your help/any tips you can provide! I appreciate you reading through this long post, and I am open to suggestions!
template<class...Ts>
using operation = void(*)(void* t, void*state, Ts...);
template<class...Ts>
struct invoker{
operation<Ts...> f;
std::shared_ptr<void> state;
void operator()(void* t, Ts...ts)const{
f(t, state.get(), std::forward<Ts>(ts)...);
}
};
template<class T, class...Ts, class F>
invoker<Ts...> make_invoker(F&& f){
return {
[](void* pt, void* state, Ts...ts){
auto* pf=static_cast<std::decay_t<F>*>(state);
(*pf)( *static_cast<T*>(pt), std::forward<Ts>(ts)... );
},
std::make_shared<std::decay_t<F>>( std::forward<F>(f) )
};
}
so how does this help? Well you can store howto erase by index using this.
std::vector<??>* allComponents = (std::vector<??>*)componentHolder[x]; // Here is where the issue lies
(*allComponents).erase((*allComponents).begin() + entityIndex);
what you want is a f(void*, int) that does the above.
template<class T>
invoker<int> erase_at_index(){
return make_invoker<std::vector<T>,int>([]( auto&&vec, int index ){
vec.erase(vec.begin()+index);
};
}
simply store std::vector<invoker<int>> erasers;. When a new type is added , push a new eraser made by erase_at_index<T>.
Then:
erasers[x](componentHolder[x],entityIndex);
and done.
The shared ptr is once per type; if that overhead is too much, aligned storage and static asserts that the F isn't too big can be used instead.

Accessing derived members from a container of base pointers

Consider the following code:
struct Object
{
bool hasComponent(std::string sComponentID);
Component& getComponent(std::string sComponentID);
std::vector<Component*> vComponents;
}
struct System
{
std::vector<Object*> vObjects;
}
My system will iterate over each Object in its vector and need to access data from derived members of Component (they all contain different state and data for the system to use).
I've considered something like this:
struct NetworkComponent : Component
{
std::string sID;
NetworkComponent(std::string tempID) : sID(tempID) {};
//Network data here
}
for(Object* p : vObjects)
{
if(p->hasComponent("network")
{
NetworkComponent& network = static_cast<NetworkComponent&>(p->getComponent("network");
//Access the data in the structure and do stuff with it.
}
}
This does however feel VERY "hacky"; not to mention unsafe.
I was wondering if there is a better way to do things like this, or at the very least how to avoid this problem in the future?
Are there any good articles written on this subject that I can look up?
EDIT: dynamic_cast is NOT an option due to how slow it is.
It sounds like you are trying to reinvent dynamic_cast
I'd refactor the getComponent method to return a pointer (a nullptr if no such component exists) instead of a reference and also pass the string argument with a constant reference:
Component * getComponent(const std::string & sComponentId);
Then you can do something like this:
template <typename CompType, typename ... Args>
CompType * getComponentOfType(Args && ... args)
{ return dynamic_cast<CompType *>(getComponent(std::forward<Args>(args)...)); }
If dynamic_cast is not an option here, use static_cast. By doing this you only lose a layer of safety for programming errors in this case.
And do something like:
for(Object * const p : vObjects) {
assert(p);
NetworkComponent * const net =
p->getComponentOfType<NetworkComponent>("network");
if (net) {
// Use the network component.
}
}
You can define class Object to contain virtual methods, which you want to have in derived classes.
Each of them should throw an exception, which mean this object didn't redefined this method.
Of course, in each of derived classes you should redefine methods that it's objects should have.

Design Pattern for caching different derived types without using RTTI

Let's say I have a family of classes which all implement the same interface, perhaps for scheduling:
class Foo : public IScheduler {
public:
Foo (Descriptor d) : IScheduler (d) {}
/* methods */
};
class Bar : public IScheduler {
public:
Bar (Descriptor d) : IScheduler (d) {}
/* methods */
};
Now let's say I have a Scheduler class, which you can ask for an IScheduler-derived class to be started for a given descriptor. If it already exists, you'll be given a reference to it. If one doesn't exist, then it creates a new one.
One hypothetical invocation would be something like:
Foo & foo = scheduler->findOrCreate<Foo>(descriptor);
Implementing that would require a map whose keys were (descriptor, RTTI) mapped to base class pointers. Then you'd have to dynamic_cast. Something along these lines, I guess:
template<class ItemType>
ItemType & Scheduler::findOrCreate(Descriptor d)
{
auto it = _map.find(SchedulerKey (d, typeid(ItemType)));
if (it == _map.end()) {
ItemType * newItem = new ItemType (d);
_map[SchedulerKey (d, typeid(ItemType))] = newItem;
return *newItem;
}
ItemType * existingItem = dynamic_cast<ItemType>(it->second);
assert(existingItem != nullptr);
return *existingItem;
}
Wondering if anyone has a way to achieve a similar result without leaning on RTTI like this. Perhaps a way that each scheduled item type could have its own map instance? A design pattern, or... ?
The address of a function, or class static member, is guaranteed to be unique (as far as < can see), so you could use such an address as key.
template <typename T>
struct Id { static void Addressed(); };
template <typename ItemType>
ItemType const& Scheduler::Get(Descriptor d) {
using Identifier = std::pair<Descriptor, void(*)()>;
Identifier const key = std::make_pair(d, &Id<ItemType>::Addressed);
IScheduler*& s = _map[key];
if (s == nullptr) { s = new ItemType{d}; }
return static_cast<ItemType&>(*s);
}
Note the use of operator[] to avoid a double look-up and simplify the function body.
Here's one way.
Add a pure virtual method to IScheduler:
virtual const char *getId() const =0;
Then put every subclass to it's own .h or .cpp file, and define the function:
virtual const char *getId() const { return __FILE__; }
Additionally, for use from templates where you do have the exact type at compile time, in the same file define static method you can use without having class instance (AKA static polymorphism):
static const char *staticId() { return __FILE__; }
Then use this as cache map key. __FILE__ is in the C++ standard, so this is portable too.
Important note: use proper string compare instead of just comparing pointers. Perhaps return std::string instead of char* to avoid accidents. On the plus side, you can then compare with any string values, save them to file etc, you don't have to use only values returned by these methods.
If you want to compare pointers (like for efficiency), you need a bit more code to ensure you have exactly one pointer value per class (add private static member variable declaration in .h and definition+initialization with FILE in corresponding .cpp, and then return that), and only use the values returned by these methods.
Note about class hierarchy, if you have something like
A inherits IScheduler, must override getId()
A2 inherits A, compiler does not complain about forgetting getId()
Then if you want to make sure you don't accidentally forget to override getId(), you should instead have
abstract Abase inherits IScheduler, without defining getId()
final A inherits Abase, and must add getId()
final A2 inherits Abase, and must add getId(), in addition to changes to A
(Note: final keyword identifier with special meaning is C++11 feature, for earlier versions just leave it out...)
If Scheduler is a singleton this would work.
template<typename T>
T& Scheduler::findOrCreate(Descriptor d) {
static map<Descriptor, unique_ptr<T>> m;
auto& p = m[d];
if (!p) p = make_unique<T>(d);
return *p;
}
If Scheduler is not a singleton you could have a central registry using the same technique but mapping a Scheduler* / Descriptor pair to the unique_ptr.
If you know all your different subtypes of IsScheduler, then yes absolutely. Check out Boost.Fusion, it let's you create a map whose key is really a type. Thus for your example, we might do something like:
typedef boost::fusion::map<
boost::fusion::pair<Foo, std::map<Descriptor, Foo*>>,
boost::fusion::pair<Bar, std::map<Descriptor, Bar*>>,
....
> FullMap;
FullMap map_;
And we will use that map thuslly:
template <class ItemType>
ItemType& Scheduler::findOrCreate(Descriptor d)
{
// first, we get the map based on ItemType
std::map<Descriptor, ItemType*>& itemMap = boost::fusion::at_key<ItemType>(map_);
// then, we look it up in there as normal
ItemType*& item = itemMap[d];
if (!item) item = new ItemType(d);
return item;
}
If you try to findOrCreate an item that you didn't define in your FullMap, then at_key will fail to compile. So if you need something truly dynamic where you can ad hoc add new schedulers, this won't work. But if that's not a requirement, this works great.
static_cast the ItemType* to void* and store that in the map.
Then, in findOrCreate, just get the void* and static_cast it back to ItemType*.
static_casting T* -> void* -> T* is guaranteed to get you back the original pointer. You already use typeid(ItemType) as part of your key, so it's guaranteed that the lookup will only succeed if the exact same type is requested. So that should be safe.
If you also need the IScheduler* in the scheduler map just store both pointers.

C++ polymorphism with template interface

Timer.h:
template<class T>
class Timer {
public:
typedef T Units;
virtual Units get() = 0;
};
TimerImpl.h:
class TimerImpl: public Timer<long> {
public:
TimerImpl() {
}
~TimerImpl() {
}
long get();
};
FpsMeter.h(version 1):
template <class T>
class FpsMeter {
private:
Timer<T>* timer;
public:
FpsMeter (Timer<T>* timer) {
this->timer = timer;
}
...
};
This example works. But it does not look pretty.
Timer<long>* t = new TimerImpl();
FpsMeter<long>* f1 = new FpsMeter<long> (t);
Here there are a lot of extra template uses. How can I realize this idea of multy-type interface when the type is defined by the implementation and user class has not to define new type, it should use the type of the implementation.
If you don't mind a helper template function which always creates FpsMeter on the heap you could something like the following
template < class T >
FpsMeter<T> *make_FpsMeter( Timer<T> *timer ) {
return new FpsMeter<T>( timer );
}
Then creating a FpsMeter of the appropriate type is like so
FpsMeter<long> *f1 = make_FpsMeter( new TimerImpl() );
Or if you can use C++11 auto you'd get
auto f1 = make_FpsMeter( new TimerImpl() );
This is the best you can do in C++, as far as I know. FpsCounter needs to know the type T so that it knows which Timer<T> implementations it can accept. Your sample code can be made somewhat simpler:
FpsMeter<long>* f1 = new FpsMeter<long> (new TimerImpl());
...which at least gets you out of repeating the template type, but of course in that case FpsMeter must take responsibility for deleting the TimerImpl, ideally through an auto_ptr or such.
I'd question, too, whether you really need to vary the return value of get(). What sorts of values do you expect it to return, besides long?
Maybe you can take inspiration from the <chrono> library from C++11 (also available in boost). Or better yet, save yourself some time and just use it directly. It's efficient, safe, flexible, and easy to use.
If you want to use only timers based on implementation of machine timer (which should be defined at compilation stage for entire program I assume), i would simply use typedef and perhaps some preprocessor magic to get it right:
[...]
#if TIMER_LONG // Here you should somehow check what type is used on target platform.
typedef Timer<long> implTimer;
typedef FpsMeter<long> implFpsMeter;
#else // If eg. using double?
typedef Timer<double> implTimer;
typedef FpsMeter<double> implFpsMeter;
#fi
This should make user code unaware of actual typee used, as long it is using implTimer and implFpsMeter.
If you mean that some parts of code will use different TimerImpl then you should make your FpsMeter class polymorphic
class FpsMeter{
public:
virtual double fps()=0;
virutal void newFrame()=0;
[...]
//Class counts new frames and using internal timer calculates fps.
};
template <typename T>
class FpsMeterImpl: public FpsMeter{
TimerImpl<T>* timer;
public:
FpsMeterImpl(TimerImpl<T>* timer);
virtual double fps();
virutal void newFrame();
};

templated abstract factory class with pooling

I'm working on a game engine component that handles events. What I'm trying to do is create a system that I can register new event types by name. The event manager will then hold a collection of event types and the factories to generate such an event type BUT the twist is that I want to make it used a pooling system such that I create an event, use it and then rather than deleting it, throw it into a list. Next time I create that event, rather than using the heap, I can just allocate from the pool.
SO given these hierarchy of event types...
struct TEvent
{
int nID;
int nTimeStamp;
};
struct TCollisionEvent : public TEvent
{
TEntity* pEntity1;
TEntity* pEntity2;
Vector3* pvecPoint;
};
I then created a smart factory which does this creation/recyling operation:
template <class BASE_CLASS>
class CSmartFactory
{
private:
typedef typename std::list<BASE_CLASS*> TBaseList;
typedef typename std::list<BASE_CLASS*>::iterator TBaseListItr;
TBaseList* m_plstPool;
public:
explicit CSmartFactory()
{
m_plstPool = NULL;
}
~CSmartFactory()
{
TBaseListItr itr;
if (m_plstPool)
{
for (itr = m_plstPool->begin(); itr != m_plstPool->end(); itr++)
{
BASE_CLASS* pEntity = *itr;
SAFE_DELETE(pEntity);
}
m_plstPool->clear();
SAFE_DELETE(m_plstPool);
}
}
bool Init(int nPoolSize)
{
bool bReturn = false;
do
{
m_plstPool = new TBaseList;
IwAssert(MAIN, m_plstPool);
while (nPoolSize--)
{
BASE_CLASS* pBaseObject = new BASE_CLASS;
IwAssert(MAIN, pBaseObject);
m_plstPool->push_back(pBaseObject);
}
bReturn = true;
} while(0);
return bReturn;
}
BASE_CLASS* Create()
{
BASE_CLASS* pBaseObject = NULL;
//
// grab a pre-made entity from the pool or allocate a new one
if (m_plstPool->size() > 0)
{
pBaseObject = m_plstPool->front();
m_plstPool->pop_front();
pBaseObject->Clear();
}
else
{
pBaseObject = new BASE_CLASS;
IwAssert(MAIN, pBaseObject);
}
return pBaseObject;
}
void Recycle(BASE_CLASS* pBaseObject)
{
m_plstPool->push_back(pBaseObject);
}
};
SO now I can do this:
CSmartFactory<TCollisionEvent>* pCollisionEventFactory = new CSmartFactory<TCollisionEvent>;
BUT what I want to do is have my event manager allow for dynamic event registration but that's where I run into my snag.
Ideally RegisterEvent will track the name and factory pointer in an stl::map or something but not quite sure how to get to that point. Maybe I've gone down the wrong path altogether.
This compiles
class TEventManager
{
public:
TEventManager();
~TEventManager();
bool RegisterEvent(char* pszEventName, CSmartFactory<TEvent>* pFactory);
};
Until you add
TEventManager::RegisterEvent("CollisionEvent", new CSmartFactory<TEntityCollisionEvent>);
So now I'm hopelessly trying to find a way to make this all work.
Anybody got some ideas here!?
Fred
I assume that you want to reuse events to avoid expensive heap malloc/free's?
I think the right answer here is not to convolute your code by writing your own structure for reusing objects, but to use a small-object allocator. As a start, it may be worth looking into boost::pool.
The two classes CSmartFactory<TEntityCollisionEvent> and CSmartFactory<TEvent> will be generated to something like
CSmartFactory_TEntityCollisionEvent
CSmartFactory_TEvent
They are actually two separate and unrelated classes. Trying to use them interchangeably would be unwise, although they behave the same (their type classes are polymorphic right).
Dynamic casting wont work, you could however try to use brute force casting:
TEventManager::RegisterEvent("CollisionEvent",
reinterpret_cast<CSmartFactory<TEvent>*>(new CSmartFactory<TEntityCollisionEvent>));
Warning: At your own risk! ;-)
OK so after a lot of head banging, I realized the solution is FAR simpler than what I was trying to pull off.
All the manager should care about is managing a TEvent*. Each TEvent has a unique hash value that makes it unique so when a new event is added both the string name and hash name of that even is stored. So from there I can add a pointer to any subclass so long as it's casted to TEvent.
I was making it FAR more complex than it needed to be.