2016-09-12 11 views
-1

最近、私は添字演算子のマップについて混乱しました。たとえば のために、コードがC++添字演算子について

#include <map> 

class A{ 
public: 
    int a; 
    A(){cout << "default constructor" <<endl;} 
    A(int a){ 
     cout << "user_defined constructor" <<endl; 
     this->a = a; 
    } 
    A(const A& tmp){ 
     cout << "copy constructor" <<endl; 
     this->a = tmp.a; 
    } 
    A& operator= (const A& tmp){ 
     cout << "assign constructor" <<endl; 
     this->a = tmp.a; 
     return *this; 
    } 

}; 
int main(){ 
    std::map<int, A> m; 
    m[1] = A(1); // error occur right? 
    m.insert (make_pair(1,A(1))); // ok 
} 

以下のようになります。私たちはコードを書く時に何が起こったかを知ってほしいです。

m[1] = A(1); // it will first make a empty pair ? right? 

m.insert (make_pair(1,A())); // here call default constructor 

次に、代入コンストラクタまたはコピーコンストラクタを呼び出しますか? 出力は

user_defined constructor 
default constructor 
copy constructor 
copy constructor 
assign constructor 

あなたはどうもありがとう、私に詳細を説明することができます。

+0

'A'はデフォルトで構成可能ではありません。' map'の値はできません。 – KABoissonneault

+2

@KABoissonneault:可能です。その場合、 'operator []'を使うことはできません。 –

+0

どのような "詳細"が必要ですか? – Hayt

答えて

3

あなたが書いた:

m[1] = A(1); 

最初のマップは1のキーを持つエントリを探します。それが見つからない場合、そのキーで新しいエントリを作成しようとします。デフォルトの構成のAオブジェクトが作成されます。 Aクラスはデフォルトで構築可能ではないため、これはコンパイルに失敗します。

しかし、そうではないと仮定すると、この新しく作成されたAオブジェクト(またはキーが見つかった場合はすでに存在していたものへの参照)への参照が返されます。これはすべてm[1]式で発生します。残りの文= A(1)は、新しいAオブジェクトを作成し、m[1]から返された参照に割り当てます。

+0

それはあなたが最初にAのデフォルトのコンストラクタを呼び出し、次にAのユーザ定義のコンストラクタを呼び出し、最後にAの代入コンストラクタを呼び出せることを意味しますか? –

+0

@ArthurGeorge:はい。デフォルトのコンストラクタ呼び出しと 'A(1)'への明示的な呼び出しの順序は、実装定義されていますが。逆の場合があります。 –

+0

@Benjamin Lindleyに感謝します。しかし、私は上記のセグメントコードにいくつかのテストコードを追加します。出力結果は次のとおりです。Aのuser_definedコンストラクタ - > Aのデフォルトコンストラクタ - > Aのコピーコンストラクタ - > Aのコピーコンストラクタ - > Aのコンストラクタ割り当て。はい、oneuser_definedコンストラクタ、1つのデフォルトコンストラクタ、2つのコピーコンストラクタ、コンストラクタを割り当てます –

1

呼び出される関数を知りたい場合は、デバッガでブレークポイントを設定するだけです。その最初の構造:あなたは

  1. コンストラクタA(int)
  2. デフォルトコンストラクタA()(コンパイルに追加しなければならない)
  3. A& operator=(const A& other)

だから何が起こるかはかなり明確であるために、そのm[1] = A(1);のコールが表示されますA(1)を検索し、マップ内のキー1を検索して見つからない場合は、デフォルトのAを挿入し、最後にA(1)に置き換えます。

これはデバッグビルドで発生します。上記の操作の一部を回避するには、リリースビルドをoptimizedにすることができます。これらの機能でプリントを追加して、完全に確実にしてください。

コピー回数を最小限に抑える場合は、m[1] = A(1)の代わりにm.emplace(1,1)を使用してください。コンストラクタA(int)を呼び出すだけで、デフォルトコンストラクタも代入演算子も呼び出されません。

+0

ありがとう、私はちょうどいくつかのプリントを出力し、Aのuser_definedコンストラクタ - > Aのデフォルトコンストラクタ - > Aのコピーコンストラクタ - > Aのコピーコンストラクタ - > Aのコンストラクタ割り当てのように出力します。 –

+0

あなたの質問に対する答えはありますか? –

+0

デバッガを使ってブレークポイントを設定することについてのあなたの考えは本当に役に立ちます。ちなみに、2つのコピーコンストラクタがある理由は、@Benjamin Lindleyによって答えられています。再度、感謝します。 –

関連する問題