web-dev-qa-db-ja.com

std :: map内のポインターを適切に破棄する

次のように宣言されたマップがあります

std::map<std::string, Texture*> textureMap;

テクスチャファイルへのパスを実際のテクスチャにペアリングするために使用します。これにより、個々のスプライトに対して同じテクスチャを何度もロードすることなく、パスによってテクスチャを参照できます。方法がわからないのは、ResourceManagerクラスのデストラクタ内のテクスチャを適切に破棄することです(マップがある場所)。

私はこのようなイテレータでループを使用することを考えました:

ResourceManager::~ResourceManager()
{
    for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
    {
        delete (*itr);
    }
}

しかし、それは機能しません、それは削除がポインターを期待したと言います。かなり遅いので、たぶん明らかな何かを見逃しているかもしれませんが、就寝前にこれを機能させたかったのです。それで、私はこれで近づいていますか、それとも完全に間違った方向にいますか?

28
Mike

サンプルコードに関する限り、ループ内でこれを行う必要があります。

_delete itr->second;
_

マップには2つの要素があり、2番目の要素を削除する必要があります。あなたの場合、_itr->first_は_std::string_であり、_itr->second_は_Texture*_です。

特定のエントリを削除する必要がある場合は、次のようにすることができます。

_std::map<std::string, Texture*>::iterator itr = textureMap.find("some/path.png");
if (itr != textureMap.end())
{
    // found it - delete it
    delete itr->second;
    textureMap.erase(itr);
}
_

エントリがマップに存在することを確認する必要があります。存在しない場合、テクスチャポインタを削除しようとすると例外が発生する可能性があります。

別の方法として、生のポインタの代わりに_std::shared_ptr_を使用し、couldより簡単な構文を使用してマップからアイテムを削除し、必要に応じて、_std::shared_ptr_が基になるオブジェクトの削除を処理するようにします。そのように、次のように、キー引数とともにerase()を使用できます。

_// map using shared_ptr
std::map<std::string, std::shared_ptr<Texture>> textureMap;

// ... delete an entry ...
textureMap.erase("some/path.png");
_

それは2つのことを行います:

  • エントリが存在する場合、マップから削除します
  • _Texture*_への他の参照がない場合、オブジェクトは削除されます

_std::shared_ptr_を使用するには、最新のC++ 11コンパイラまたは Boost が必要です。

42
Roger Rowland

答えはループの問題を完全には解決しませんでした。少なくともCoverty(TM)では、ループ内でイテレーターを消去することはできませんが、それを使用してループを続行します。とにかく、メモリを削除した後、マップ上でclear()を呼び出すと残りの処理が行われます。

ResourceManager::~ResourceManager()
{
    for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
    {
        delete (itr->second);
    }
    textureMap.clear();
}
1
charo

ジョブに適切なツールを使用していません。

ポインターはデータを「所有」しないでください。

つかいます - boost::ptr_map<std::string, Texture> 代わりに。

1
Mehrdad