2017-12-31 161 views
2

明示的に宣言されたデフォルト/コピーコンストラクタの違いは何ですか? は明示的に、また明示的に定義された明示的コンストラクタ対暗黙的に定義されたコンストラクタ

road::road(){} 

road::road(const road & c_road):id(c_road.id)), type(c_road.type)), 
    nodes(c_road.nodes){} 

私の質問があるように私自身のコンストラクタを定義するとの違いは何ですか暗黙

struct road{ 
std::string id; 
std::string type; 
std::vector<int> nodes; 
road(road && m_road); 
}; 

を定義し

struct road{ 
    std::string id; 
    std::string type; 
    std::vector<int> nodes; 
    road() = default; 
    road(const & road c_road) = default; 
    road(road && m_road); 
    }; 

を宣言し、私は明示的にデフォルトコンストラクタを宣言する必要があります(=デフォルト;バージョン)、暗黙的に依存するだけでいいですか?どのようなバージョンもどんな方法でも速く、安全ですか?どのバージョンが間違っていますか?

答えて

1

「ルールのゼロ」を調べるとよいでしょう。あなたのクラスは、メンバーがすでにコピー/移動コンストラクタを定義しているメンバワイズコピーを実行するため、コンストラクタは必要ありません。リソースを管理したり、扱いにくいタイプを扱わなければならない場合は、別の話になります。理想的には、あなたのクラスは次のようになります。

struct road{ 
    std::string id; 
    std::string type; 
    std::vector<int> nodes; 
}; 

あなたはコピーコンストラクタをユーザーが宣言したが、移動のコンストラクタを省略した場合、コンパイラはないはあなたのための移動のコンストラクタを生成します。だからあなたは3つすべてが必要です。同様に、代入演算子を実装する場合は、コピー代入/移動代入の両方が必要です。これはそれぞれ3/5のルールとして知られています。簡単にして、必要なものだけを定義してください。

+0

私は次のように考えています。コピー(または移動)ではないコンストラクタを追加すると、コンパイラのコピー(および移動)がコンパイラによって生成されなくなります**。 – Zereges

+0

また、コンパイラが不要なctorsまたは割り当てを生成しないようにするには、 "... = delete;"を使用します。宣言例: "T(const T&)= delete;"コピーを許可しないか、または "T&operator =(const T &&)= delete;"移動割り当てを禁止する。 –

0

明示的にデフォルト(インライン)と暗黙的にデフォルトに設定されています:ここではほとんど違いがありません。それは主に文体の選択です。個人的には、小さなクラス(< 1つのスクリーン)の場合、どこにも定義されていないのが分かりやすいので気にしません。クラスに長さを追加します。

もっと重要なクラスについては、明示的にするのが良いことです。これは、値のセマンティクス(少なくとも可動)または識別意味(不動)、コピー可能であるかどうか、不変(その場合は割り当て不可)などがあるかどうかを即座にユーザーに通知します。

違いは、あなたがスペシャルメンバーのいくつかを宣言すると、他のメンバーは暗黙的に生成されないということです。最も一般的な例は、コピーコンストラクタ/代入を自分で実装する必要がある場合です。これにより、移動コンストラクタ/割り当ての自動生成が無効になります。そのため、明示的にデフォルト値を設定する必要があります(デフォルト値が必要な場合)。

多くの人が光り輝くもう1つの重要な違い:クラスが.hと.cppファイルに分割されている場合(ほとんどの非テンプレートクラスがそうでなければならないため)、これらのアプローチは両方とも、ヘッダ。これによりコンパイルが遅くなります。そこで、第三のアプローチは、これを行うことです。

// .h file 
struct Foo { 
    Foo(const Foo&); // declare, but not define 
}; 

// .cpp 
Foo::Foo(const Foo&) = default; 

これはまだ生成されたメンバーを利用していますが、あなたがそれをしたい.cppファイルのコードを保持します。したがって、テンプレートではない大きなクラスの場合は、通常は=deleteにするか、宣言しますが、=defaultを宣言しないでください。暗黙的に生成されるようにしてください。

あなたの特別なメンバーを定義する限り、デフォルトが機能する場合は特別なメンバーを決して定義するべきではありません。そして、デフォルトを有効にしようとするべきです。コンストラクターを自分で定義するときは、一般的に各メンバーを一度言及する必要があります。メンバを追加または削除すると、メンテナンスが必要になります。メンテナンスには、忘れてしまったメンテナンスも含まれます。ゼロのルール:http://www.nirfriedman.com/2015/06/27/cpp-rule-of-zero/を参照してください。

特別なケースの1つ:デフォルトコンストラクタ。他のコンストラクタがあれば、暗黙的に生成されることはありません。あなたがそれを元に戻したいのであれば、=defaultと同じように簡単に見え、それを簡単に定義するだけです。これらは同じではありません。特に、後者は依然としてユーザー定義のコンストラクタとしてカウントされます。つまり、クラスがtrivially_constructibleと決して考慮されないため、trivialではないため、podにはなりません。これは、一部のアプリケーションでは重要です。

+0

ありがとうございました。あなたのリンクは特に役立った、私は私のC + +の知識は今より完全だと思う。私はあなたの答えを受け入れることができませんでした。なぜなら、他のユーザーがおそらくあなたより多くの担当者を必要としているからです。 あなたは価値/アイデンティティーのセマンティクスについて詳しく説明できますか? – Konstantinoscs

+0

@ Constructinoscs値の意味は整数のようになります。あなたはそれをコピーすることができ、等価は整数の値に基づいて決定されます。特に多態性クラスは、値のセマンティクスを持たないかもしれません。ベースポインタで何かを保持すると、コピーできないことがあります。しばしば大きくて複雑なので、単純な値に基づく等価比較も容易ではありません。したがって、そのようなクラスをコピー不可能にすることを選ぶことができます。また、それらが同一のオブジェクトである場合にのみ、それらのクラスに同一性を与えます。それは大きな話題です、おそらくGoogleにしたいです:-)。 –

関連する問題