2013-04-14 100 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. 
}