要添加到矢量的函数结束后,矢量将丢失对条目的引用

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

本文关键字:引用 添加 函数 结束      更新时间:2023-10-16

我正在实现一个实体组件系统,当我试图将组件添加到实体时遇到了问题。这样做的结构如下:

下面将找到一个ID为0的实体,并为其添加一个仓位组件。

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;
        }
    }
}

上面只是一个助手函数,首先找到实体,然后它会调用下面的函数:

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;
        }
   }
}

此功能将查找未分配(空闲、可用、未添加到实体)的职位组件并将其返回。

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];
        }
    }
}

最后,在实体内部,我们有这个功能:

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

实体被保存在EntityManager内部的向量中,作为堆栈上的普通对象创建。这与ComponentManager内部的Position组件相同。

我的目标是将所有组件保留在ComponentManager中,系统向ComponentManager请求以某种方式处理组件。我想为每个实体保留指针或引用,指向它所拥有的组件。

我的问题是,一旦Entity::addComponent()完成,m_componentVector向量就不再包含添加到它的Component,就像它正在脱离范围一样。我想问题出在我传递副本而不是推荐信的地方?我最初把参数作为指针,但一直在尝试修复它。

注释中的相关事实:Entity::m_componentVector被定义为

std::vector<Component> m_componentVector;

这是一个存储Component对象而非引用的向量。因此,在Entity::addComponent中,线

m_componentVector.push_back(component);

将复制component引用的对象并将其添加到向量中。此副本独立于从中复制的对象。

更糟糕的是,addComponentcomponent参数实际上引用了PositionComponent类型的对象(可能是从Component派生的)。在进行上述复制时,将只复制与基类Component相对应的部分。这被称为切片-派生类添加的部分被简单地"切片"。

您希望使实体的m_componentVector引用存储在ComponentManager中的组件。不能将引用存储在向量中。您可以存储指针,但如果向向量中添加了其他元素,指向向量元素的指针可能会无效(也就是说,如果您存储了指向m_positionComponentVector[0]的指针,后来又向m_positionComponentVector添加了更多元素,因此需要重新分配,则存储的指针将变为无效)。因此,存储索引是最安全的选择。