【问题标题】:Vector losing reference to entries after function to add to vector finishes向量在添加到向量完成后失去对条目的引用
【发布时间】:2014-08-28 07:41:39
【问题描述】:

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

下面会找到一个ID为0的Entity,并为其添加一个Position组件。

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

上面只是一个辅助函数,先找到Entity,然后它会调用下面的函数:

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

最后,在 Entity 内部我们有这个函数:

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

实体保存在 EntityManager 内的向量中,在堆栈上创建为普通对象。 ComponentManager 中的 Position 组件也是如此。

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

我的问题是,一旦 Entity::addComponent() 完成,m_componentVector 向量不再包含添加到它的组件,就像它超出范围一样。我认为问题出在我传递副本而不是参考的地方?我最初将参数作为指针,但正在尝试修复它。

【问题讨论】:

  • 您是否要让Entity 的m_componentVector 持有对getUnassignedPositionComponent() 返回的组件的引用?您不能将引用存储在容器中。
  • 刚才声明为std::vector m_componentVector,所以是Component实例的向量。
  • 然后你将Component 的副本推入向量中(如果PositionComponent 是Component 的派生类,看起来很可能,那么复制也切割了对象) .
  • 好吧,这听起来很可能,你能描述一下我如何确保我推送的是对组件的引用而不是它的副本吗?我会研究切片,谢谢。
  • 不存储引用,而是存储索引。引用向量中的元素,所有类型的事情都会变坏。

标签: c++ entity-framework vector


【解决方案1】:

来自 cmets 的相关事实:Entity::m_componentVector 定义为

std::vector<Component> m_componentVector;

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

m_componentVector.push_back(component);

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

更糟糕的是,addComponent 的 component 参数实际上引用了 PositionComponent 类型的对象(大概是从 Component 派生的)。在进行上述复制时,只会复制与基类Component 对应的部分。这被称为 slicing - 派生类添加的部分被简单地“切掉”。

您想让实体的m_componentVector 引用存储在ComponentManager 中的组件。您不能将引用存储在向量中。您可以存储指针,但如果将其他元素添加到向量中,则指向向量元素的指针可能会失效(即,如果您存储指向 m_positionComponentVector[0] 的指针,然后将更多元素添加到 m_positionComponentVector 以便重新分配必要时,您存储的指针将变为无效)。因此,存储索引是您最安全的选择。

【讨论】:

  • 感谢您提供的信息丰富的回答。我现在意识到究竟是什么导致了这个问题。您关于使用索引的建议似乎是明智的,我之前考虑过这一点,并认为传递引用或指针可能更简单,但您提出的问题肯定会导致一些令人头疼的问题。我不知道切片,所以很高兴知道。为了推进,我想我将编辑我的代码以使用与引用相对的索引。感谢您的帮助。
猜你喜欢
  • 2016-04-14
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-27
相关资源
最近更新 更多