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 から移動するため、最初の2つのうちの1つに傾いています。これは私がやりたくないことです。

情報を渡す際に従うべき簡単なルールはありますか? いつ参照を使用し、いつ shared_ptr を使用する必要がありますか?

4

1 に答える 1

1

所有権のセマンティクスを使用する場合、参照に対して次の基本的なアプローチを使用します。

  • 関数パラメーターによる参照の取得。関数はこのオブジェクトを使用しますが、関数の存続期間を超えて参照を保存することはありません。関数が返されたら、ぶら下がっている参照やポインターを心配することなく、安全にオブジェクトを破棄できます。
  • 参照を返します。オブジェクトを自由に使用できますが、それを所有しておらず、参照を返すオブジェクトの存続期間を超えて参照を保存することはできません。

quadTree強いポインターの代わりに参照を受け入れて返すように を変更すると、これら 2 つの規則に違反しているように見えます。それは問題ありませんが、追加の変更が必要です。あなたの場合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 に答える