2013-07-25 14 views
8

私はに文字列値をマップするのにstd::mapを使用しています。マイマップの宣言は次のようになります。ポインタ値を持つマップを破壊する適切な方法

map<string, MyType *> *my_map = new map<string, MyType>; 

my_mapは私のクラスの一つのプライベートメンバ変数です。私の問題は、マップを破壊する方法がわからないことです。地図を削除する際には、地図に含まれているMyType *のすべてにdeleteと電話したいと思います。ここに私の現在のデストラクタは、次のとおりです。

my_map->erase(my_map->begin(), my_map->end()); 
delete my_map; 

これがマップに含まれているポインタを削除しますか、私は消去呼び出す前に、各ポインタを削除するには、マップを反復処理する必要がありますか?

+2

'map'(および標準ライブラリの大部分(すべてではないにしても)の大部分のコンテナ)は、破壊時に含まれるポインタを削除するようには設計されていません。 – Nbr44

+0

ありがとう。私が読んだドキュメントはあまり明確ではありませんでした。 'これは、削除された要素の数だけコンテナサイズを効果的に減らします。それは破壊されます。 ' – Max

+3

これは一般的な誤解です - _pointers_自体は実際には破壊されますが、それらが指し示すメモリ位置の状態は変わりません。 – Nbr44

答えて

9

ポインタは単なるポイントです。生のポインタを使うときは、ポインタの指すリソースをあなたのアプリのどの部分が所有しているのか知る必要があります。それらがマップによって所有されている場合、マップを反復処理し、マップが破棄される前に各ポインターのdeleteを呼び出す必要があります。しかし、マップがコードの他の部分が所有するオブジェクトへのポインタを保持しているだけなら、何もする必要はありません。

shared_ptrを使用してオブジェクトの有効期間を管理すると、最後のshared_ptrが破棄されたときにオブジェクトが正しく削除されます。 map内にshared_ptrsを格納できます。他のshared_ptrインスタンスがマップ内のオブジェクトを参照していない場合は、必要に応じてマップが破棄されたときにオブジェクトが破棄されます。

2

生ポインタの代わりにsmart pointersを使用すると、自動的にすべてがクリーンアップされます。

// header: 
using MapType = std::map<std::string, std::shared_ptr<MyType>>; 
shared_ptr<MapType> my_map; 

// usage: 
my_map.emplace("foo", std::make_shared<MyType>()); 

// destructor: 
MyClass::~MyClass() 
{ 
    // nothing! 
} 
3

これは[...]マップに含まれているポインタを削除しますか?

いいえ、指定したコードでは、マップのすべてのメンバーがリークします。

通常、newごとに一致するdeleteが必要です。マップにはdeleteがありますが、その中の要素はありません。

この問題の最も適切な解決策は、動的割り当てをまったく使用しないことです。可能な場合だけ、MyTypeのディレクトリを格納します。

map<string, MyType>

...、代わりに動的にmap自体を確保するので、自動的に店舗:

map<string,MyType> my_map; 

を自動記憶域期間は、いくつかのために不可能な場合理由は、動的割り当てにスマートポインタを使用します。 C++コンパイラ11与えられ、mapの要素のためunique_ptr(または、まれに、shared_ptrあるいはweak_ptr)を使用:

map<string, unique_ptr<MyType>> my_map; 

(そのブースト等価物を使用し、C++コンパイラ03を考えます。)そして、my_mapが破壊されると、すべての要素はdelete dになります。で

struct deleter 
{ 
    template <typename T> operator() (const T& rhs) const 
    { 
    delete rhs.second; 
    } 
}; 

for_each (my_map->begin(), my_map->end(), deleter()); 

:あなたが上記のいずれもがあなたのために動作しません状況(私は非常に疑うことである)である場合

ベアリング・このすべて、あなたは、マップyouselfを反復処理する必要があります。 C++ 11、これはラムダ、の線に沿って何かを作ることができる:現代のC++では

for_each (my_map->begin(), my_map->end(), [](auto item) -> void 
{ 
    delete item.second; 
}); 
1

を、ちょうど厳密に必要であれば、あなたの人生を容易にし、使用ポインタのみします。

あなたはこのコードを開始しました:あなたが行うことができます

map<string, MyType *> *my_map = new map<string, MyType>; 

最初のものではなく、それにポインタの、データメンバーとしてstd::mapインスタンスを使用することを検討することです。 MyTypeコピーする超高価ではありませんし、そのインスタンスは、地図のみによって所有されている場合

すると、ちょうど(代わりにMyType*の)MyTypestringから簡単なmapを考慮してください。

// my_map data member - no pointers --> automatically deleted in class destructor 
map<string, MyType> my_map; 

ますもし本当にポインタを含むマップが必要です。スマートポインタ(共有所有権の場合はstd::shared_ptr(C++ 11/14で利用可能)、ユニークな非共有所有権の場合はstd::unique_ptrなど)を使用することを検討してください。
(あなたがC++ 98/03をターゲットにする場合、オプションはboost::shared_ptrを使用することです何の動きの意味がありませんので、あなたが頻繁に移動セマンティクスの機能に基づいてunique_ptrを持つことはできません。。)
例:

// Map containing _smart_ pointers 
//  --> default destructor is fine (no need for custom delete code) 
map<string, shared_ptr<MyType>> my_map; 

あなたが(代わりに生のポインタの)値のセマンティクス、またはスマートポインタを使用して、見ることができるように、あなたはあなたのコードを簡素化し、C++で提供さ自動破壊を使用することができます。