查询有关正确使用智能指针的信息

时间:2013-04-14 17:09:45

标签: c++ c++11

我的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?

1 个答案:

答案 0 :(得分: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.
}