1

我的 entityManager 中有以下代码。

void GameObjectManager::updateAll(float frametime)
{   
checkAlive();

    // iterate through the entityManager, updating each entity and then adding it into the quadTree.
    for (auto itr = _gameObjects.begin(); itr != _gameObjects.end(); itr++)
    {
        itr->second->Update(frametime);

        tree->AddObject(itr->second);       
    }   

    // iterate once again through the entityManager but this time checking itself against the quadTree.
    for (auto x = _gameObjects.begin(); x != _gameObjects.end(); x++)
    {
        std::vector<std::unique_ptr<Entity>> returnObjects = tree->GetObjectsAt(x->second->GetPosition().x, x->second->GetPosition().y );       

        for ( int n = 0; n < (int)returnObjects.size(); n++ ) 
        {
            std::unique_ptr<Entity>& collided = returnObjects[n];

            if(object->getEntityName() != collided->getEntityName())
            {
                if(object->GetBoundingRect().intersects(collided->GetBoundingRect()))
                {
                    object->Touch(collided);
                }
            }
        }       
    }   
    tree->Clear();
}

在这个例子中,智能指针的正确用法是什么?当我将实体添加到四叉树时,我应该创建一个 shared_ptr,将其作为参考传递还是使用 std::move?我倾向于前两个中的一个,因为移动指针的所有权会将它从 std::map 中移动,这是我不想做的事情。

在传递信息时我应该遵循哪些简单的规则?什么时候应该使用引用,什么时候应该使用 shared_ptr?

4

1 回答 1

1

当使用所有权语义时,我使用以下基本方法来引用。

  • 通过函数参数获取引用。该函数将使用此对象,但不会在函数的生命周期之外存储对它的引用。一旦函数返回,您就可以安全地销毁对象,而不必担心悬空引用或指针。
  • 返回参考。您可以自由使用该对象,但不拥有它,并且不能在返回引用的对象的生命周期之外存储对它的引用。

更改quadTree为接受和返回引用而不是强指针似乎违反了这两个规则。没关系,但需要进行额外的更改。在你的情况下quadTree是一个成员变量。如果发生异常,quadTree仍将包含对不属于它的对象的引用,并且可能不再存在。这可以通过使用quadTree调用函数范围的局部变量来轻松纠正。这将保证的生命周期quadTree不长于_gameObjects- 实际所有者。

这只是将第一条规则扩展为包括函数所属对象的生命周期。更改可能看起来像这样(使用指针而不是可以同样应用的引用)。

void GameObjectManager::updateAll(float frametime)
{   
    checkAlive();

    quadTree tree;

    // iterate through the entityManager, updating each entity and then adding it into the quadTree.
    for (auto itr = _gameObjects.begin(); itr != _gameObjects.end(); itr++)
    {
        itr->second->Update(frametime);

        tree.AddObject(itr->second.get());      
    }   

    // iterate once again through the entityManager but this time checking itself against the quadTree.
    for (auto x = _gameObjects.begin(); x != _gameObjects.end(); x++)
    {
        std::vector<Entity*> returnObjects = tree->GetObjectsAt(x->second->GetPosition().x, x->second->GetPosition().y );       

        for ( int n = 0; n < (int)returnObjects.size(); n++ ) 
        {
            Entity* collided = returnObjects[n];

            if(object->getEntityName() != collided->getEntityName())
            {
                if(object->GetBoundingRect().intersects(collided->GetBoundingRect()))
                {
                    object->Touch(collided);
                }
            }
        }       
    }   
    //tree.Clear(); // Called by destructor.
}
于 2013-04-15T01:40:00.347 回答