Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vector losing reference to entries after function to add to vector finishes

I am implementing an Entity Component System and am having trouble when I am attempting to add a Component to an Entity. The structure of doing so is as follows:

Below will find an Entity with an ID of 0, and add a Position component to it.

m_entityManager->addComponentToEntityID(0, ComponentManager::POSITION);

void EntityManager::addComponentToEntityID(unsigned int entityID, ComponentManager::ComponentType componentType)
{
    std::shared_ptr<Entity> tempEntity;

    for (unsigned int index = 0; index < m_maximumEntities; ++index)
    {
        if (m_entityVector[index].getEntityID() == entityID)
        {
            addComponentToEntity(std::make_shared<Entity>(m_entityVector[index]), componentType);
            break;
        }
    }
}

The above is just a helper function to first find the Entity, then it will call the function below:

void EntityManager::addComponentToEntity(std::shared_ptr<Entity> entity, ComponentManager::ComponentType componentType)
{
    if (entity != nullptr)
    {
        switch (componentType)
        {
            case ComponentManager::POSITION:
                entity->addComponent(m_componentManager->getUnassignedPositionComponent());
                break;

    default:
        break;
        }
   }
}

This function will find an unassigned (free, available, not added to an Entity) Position component and return it.

PositionComponent& ComponentManager::getUnassignedPositionComponent()
{
    for (unsigned int index = 0; index < m_positionComponentVector.size(); ++index)
    {
        if (m_positionComponentVector[index].isAssigned() == false)
        {
            m_positionComponentVector[index].assign();
            return m_positionComponentVector[index];
        }
    }
}

Finally, inside of Entity we have this function:

void Entity::addComponent(Component& component)
{
    m_componentVector.push_back(component);
}

The Entities are held inside of a vector inside of EntityManager, created as normal objects on the stack. This is the same for the Position components held inside of ComponentManager.

My aim is to keep all Components inside of ComponentManager and systems make request to ComponentManager to process a component in some way. I want to keep pointers or references for each Entity, to the Components that it owns.

My problem is, once Entity::addComponent() is finished, the m_componentVector vector no longer holds the Component that was added to it, like it is falling out of scope. I think the problem is somewhere I am passing a copy instead of a reference? I originally had the parameters as pointers but was playing around trying to fix it.

like image 802
martingrant Avatar asked Nov 24 '25 06:11

martingrant


1 Answers

Pertinent fact from comments: Entity::m_componentVector is defined as

std::vector<Component> m_componentVector;

This is a vector that stores Component objects, not references. Thus, in Entity::addComponent, the line

m_componentVector.push_back(component);

will make a copy of the object referenced by component and add it to the vector. This copy is independent of the object copied from.

To make it worse, the component parameter to addComponent actually references an object of type PositionComponent (which presumably is derived from Component). In making the copy noted above, only the part corresponding to Component, the base class, will be copied. This is known as slicing - the parts added by the derived class are simply "sliced off".

You want to make Entity's m_componentVector reference the components stored in ComponentManager. You can't store references in a vector. You can store pointers, but pointers to vector elements can be invalidated if additional elements are added to the vector (that is, if you store a pointer to m_positionComponentVector[0], and later more elements are added to m_positionComponentVector such that a reallocation is necessary, the pointer you stored will become invalid). Thus, storing indices is your safest option.

like image 71
T.C. Avatar answered Nov 25 '25 19:11

T.C.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!