# Proper use of type_info in relation to mapping components to a type

I'm trying to map a components type to the component value itself in a map. The following code all works properly. My main question is this. Is storing the map key as std::type_info* the best way to accomplish what I'm doing? I'm also not digging the ugly static_cast<T*> I'm doing during the usage part.

Entity.h

#pragma once
#include "IComponent.h"
#include <map>
#include <typeinfo>

class Entity
{
public:
Entity(void);
~Entity(void);
IComponent* GetComponent(const std::type_info* typeInfo);
private:
std::map<const std::type_info*, IComponent*> components;
};


Entity.cpp

#include "Entity.h"

Entity::Entity(void)
{
}

Entity::~Entity(void)
{
for (auto &mapValue : components)
{
delete mapValue.second;
}
}

{
const type_info* info = &typeid(*component);
components.insert (std::pair<const std::type_info*,IComponent*>(info, component));
}

IComponent* Entity::GetComponent(const std::type_info* typeInfo)
{
return components.at(typeInfo);
}


Example Usage

IComponent* baseComponent = entity->GetComponent(&typeid(PerkList));
PerkList* perkList = static_cast<PerkList*>(baseComponent);

• I had the same thoughts, but it works. I -think- it has to do with how types might be defined during program execution. Such as that the type info for a particular class will always be on the stack. Although I am pulling that train of thought out of the air. – TimeEchoes Mar 16 '15 at 3:33
• Never mind, just noticed that typeid return and object with static storage. It will last for the lifetime of the program. – glampert Mar 16 '15 at 3:35
• Did you take a look at type_index? Seems more adequate for what you are doing and can be used with an unordered_map. (C++11) – glampert Mar 16 '15 at 3:37
• That's actually new to me. I'll look that up right now. – TimeEchoes Mar 16 '15 at 3:40
• @glampert It seems as though type_index is exactly what I was looking for and is meant as a clean wrapper for all the type_info usage in this case. Thank you! – TimeEchoes Mar 16 '15 at 3:45

### type_info:

Using the type_info reference is a viable approach, but it can be made better with type_index in conjunction with an unordered_map.

### static_cast:

I don't think there is a way around the cast here. You can make it slightly less verbose by defining a template helper method that wraps the type cast:

template<class T>
T * Entity::GetComponent()
{
return static_cast<T *>(components.at(&typeid(T)));
}

// Usage:
PerkList * perkList = entity->GetComponent<PerkList>();


One nice extra of this approach is that you can replace the static_cast inside with a dynamic_cast during debug/dev builds and check that the types are self-consistent. Then add a preprocessor to use the faster static_cast for a "release" build if you need to squeeze every cycle.

### Pointers:

Returning a raw pointer to IComponent is questionable to say the least. A raw pointer conveys no ownership, so it is very easy to leak or delete the objects multiple times when you have raw pointers flying around like this. You should take a look at shared_ptr and weak_ptr before further expanding your implementation. Or perhaps return just a reference (IComponent &) if the caller of GetComponent() should not own the object.

### Minor details:

• Don't add void to the parameter list of functions/methods that take no parameters. This is a C-ish style. C++ does not require that; () is just as good. So avoid the unnecessary verbosity.

• Empty destructors/constructors should be omitted or made defaults.

• I liked your added portion on the pointers. I know my implementation of them was a bit haphazard. Good advice on returning a reference instead of a raw pointer as you're indeed correct about ownership. The entity 'owns' the pointer and that's it, everything else is just borrowing it for use through GetComponent. – TimeEchoes Mar 16 '15 at 4:20