2013-04-14 33 views
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?

回答

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