2010-12-29 7 views
13

私はオブジェクトで作るどのような変化この参照によってstd :: mapのオブジェクトを取得するのは安全ですか?

map<int,object> objmap; 
object& obj = objmap.find(num)->second; 
object& obj2 = objmap[num]; 

のようなマップを持って、地図上に反映する必要があります。同様のことは、空間が必要なときにオブジェクトの位置を変えるので、ベクトルで行うことはできません。それはstd :: mapで行うのは安全ですか?それはお勧めですか? 2番目のバージョンでは、オブジェクトに空のコンストラクタがないため、エラーが発生します。何もしない空のコンストラクタを宣言すると、2つの行は同じように動作しますか?

答えて

18

問題のオブジェクトがマップから削除されない限り、安全です。地図に挿入されたオブジェクトは、他の要素が追加または削除されても移動しません。

object& obj = objmap.find(num)->second; 

キーnumを持つ要素が実際にマップに存在することを確信していない限り、これは潜在的に危険です。わからない場合は、insertのオーバーロードを使用して、iteratorboolを返します。これは、新しい要素が挿入されたか、または指定されたキーを持つ要素が既にマップに存在しているかどうかを示します。

など。

object& obj = objmap.insert(std::make_pair(num, object(arg1, arg2, argN))).first->second; 
+1

ドキュメントでこのような情報をどこでどのように見つけるか知っていますか?実際に私はこの答えを探す方法を知らなかった。「オブジェクトは動かない」と言う正しい方法は何か?私はスペックがこれを正確に定義しなければならないと思うのは、それがベクトルと地図の間に大きな違いがあるからです。 – Flynsee

11

要素がマップから削除されない限り、これは安全です。

object& obj = objmap.find(num)->second; 

マップ内のキーnumとは要素が存在しない場合は、findobjmap.end()を返します。

しかし、2行目はかなり安全ではありません。目標はすでに気づいて、けれどもoperator[]は(可能性がある呼び出し、を見つけることが、本当に挿入するために本当ににない場合は、

const std::map<int, object>::iterator it = objmap.find(num); 
if (it != objmap.end()) 
{ 
    object& obj = it->second; 
    /* ... */ 
} 

今すぐ:この可能性は返されたイテレータを逆参照する前にテストする必要があります値なしのコンストラクタを提供する必要があります)。キーが見つからない場合は、何も挿入されませんとendイテレータは常に戻り

  • operator[]
  • が返されます。

    • findのみ見つけた:しかし、あなたはこれらの2つの非常に異なるものであることを理解する必要がありますマップ内の値への参照:キーが存在しない、挿入が発生する(デフォルトの構築値のため、コンストラクタ要件)
    1

    マップ内のオブジェクトを反映させるには、オブジェクト自体ではなくオブジェクトへのポインタを格納するようにマップを変更する必要があります。参照を無効にする参照の間のオブジェクトに対して何もしない限り、参照は機能します。

    たとえば、次のコードは、参照を使用して壊す:

    object& obj = objmap.find(num)->second; 
    objmap.erase(objmap.find(num)); // should check for objmap.end() - left out for simplicity 
    obj.DoSomething(); // this object has been destroyed, so the reference is invalid 
    
    4

    あなたの質問はstd::mapは、その変異の機能にそのイテレータを無効にするかどうかであるならば、答えは否定的です。標準保証のstd::mapはイテレータを無効にしません。

    0

    キャッシングを実装する一般的な方法です。

    項目がすでに存在する場合、演算子[]はその項目を返します。存在しない場合は、デフォルトのコンストラクタで「空白」が作成され、後で使用できるように書き込むことができます。

    もちろん、作成時に値が空のvalue_typeとしてshared_ptrが一般的に使用されます。この場合、shared_ptrを参照で取得し、reset()を呼び出す必要があります。

    コレクション/キャッシュなどと同様に、マルチスレッドアプリケーションでスレッドセーフティの問題が発生している場合は、そのことに注意する必要があります。

    あなたが知りたいと思っていたことは、参照を別の場所(またはそのポインタ)に保存し、後で他のアイテムがマップに追加されたときに有効になるかどうかということでした。 。

    関連する問題