クラスの関数宣言後の「デフォルト」とはどういう意味ですか?


221

defaultクラスの関数宣言の隣で使用されているのを見てきました。それは何をするためのものか?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};

26
代入演算子の宣言で「=」の前にある「&」は何をしますか?
dshin

回答:


249

これはC ++ 11の新機能です

つまり、その関数のコンパイラー生成バージョンを使用したいので、本体を指定する必要はありません。

を使用= deleteして、コンパイラーがその関数を自動的に生成しないように指定することもできます。

ムーブコンストラクターとムーブ代入演算子の導入により、コンストラクター、デストラクタ、および代入演算子の自動バージョンが生成されるときの規則は非常に複雑になりました。使用する= defaultと、= deleteルールを覚えておく必要がないので、物事が容易になります:あなたはちょうどあなたが起こるしたいものを言います。


17
= deleteより強い:それは、その関数の使用が禁止されていることを意味しますが、それでもオーバーロードの解決には関与しています。
Deduplicator

2
しかし、コンパイラー生成定義を使用したい場合は、「最初にそれを記述してからデフォルトに割り当てる」のではなく、その関数の記述をスキップしないでください。
Mayank Jindal

47

これは、C ++ 0xの新しい機能であり、それぞれのコンストラクターまたは代入演算子のデフォルトバージョンを作成するようコンパイラーに指示します。つまり、各メンバーに対してコピーまたは移動アクションを実行するだけです。これは、コピーコンストラクター(および同様に割り当て)とは異なり、ムーブコンストラクターがデフォルトで常に生成されるとは限らないため(たとえば、カスタムデストラクタがある場合)、便利ですが、書くのが簡単でない場合は、コンパイラーは、毎回自分で綴るよりも処理します。

また、他のデフォルト以外のコンストラクターを指定した場合、デフォルトのコンストラクターが生成されないことにも注意してください。それでもデフォルトのコンストラクタが必要な場合は、この構文を使用してコンパイラに作成させることができます。

別の使用例として、コピーコンストラクターが暗黙的に生成されない状況がいくつかあります(たとえば、カスタムムーブコンストラクターを提供する場合)。それでもデフォルトバージョンが必要な場合は、次の構文でリクエストできます。

詳細については、標準のセクション12.8を参照してください。


5
ただし、コンストラクタと割り当てだけでなくoperator new/new[]operator delete/delete[]とそのオーバーロードにも適用されます。
セバスチャンマッハ

21

C ++ 11の新機能です。こちらをご覧ください。。1つのコンストラクターを定義したが、他のコンストラクターにはデフォルトを使用したい場合に非常に役立ちます。C ++ 11より前のバージョンでは、たとえデフォルトと同等であっても、一度定義したらすべてのコンストラクタを定義する必要がありました。

また、特定の状況では、コンパイラーがデフォルト値の初期化の両方で合成したコンストラクターと同じように動作するユーザー定義のデフォルトコンストラクターを提供できないことにも注意してください。defaultその動作を取り戻すことができます。


5
2番目の段落について、例を提供できますか?
John Smith

11

これらの回答で言及されていないもう1つの使用例は、コンストラクタの可視性を簡単に変更できることです。たとえば、フレンドクラスがコピーコンストラクターにアクセスできるようにしたいが、公に利用可能にしたくない場合があります。


1

C ++ 17 N4659標準ドラフト

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2「明示的にデフォルト設定された関数」:

1次の形式の関数定義:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

明示的にデフォルト設定された定義と呼ばれます。明示的にデフォルト設定されている関数は、

  • (1.1)—特別なメンバー関数であること

  • (1.2)—宣言された関数型が同じである(おそらく異なる修飾子修飾子を除き、コピーコンストラクターまたはコピー代入演算子の場合を除いて、パラメーター型は「非const Tへの参照」であり、Tはメンバー関数のクラスの名前)暗黙的に宣言されているかのように、

  • (1.3)—デフォルトの引数はありません。

2削除済みとして定義されていない明示的にデフォルト設定された関数は、暗黙的にconstexprとして宣言されている場合にのみ、constexprとして宣言できます。関数が最初の宣言で明示的にデフォルトになっている場合、暗黙の宣言がそうである場合、その関数は暗黙的にconstexprと見なされます。

3明示的にデフォルト設定されている関数が、暗黙の宣言(18.4)と同じ例外指定を生成しないnoexcept-specifierで宣言されている場合、

  • (3.1)—関数の最初の宣言で明示的にデフォルトが設定されている場合、関数は削除済みとして定義されます。

  • (3.2)—そうでない場合、プログラムの形式が正しくありません。

4 [例:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

—最後の例]

5明示的にデフォルトされた関数と暗黙的に宣言された関数は、まとめてデフォルト関数と呼ばれ、実装はそれらの暗黙的な定義(15.1 15.4、15.8)を提供する必要があります。関数は、ユーザーが宣言し、最初の宣言で明示的にデフォルトまたは削除されていない場合、ユーザー提供です。ユーザー提供の明示的にデフォルト設定された関数(つまり、最初の宣言の後に明示的にデフォルト設定された関数)は、明示的にデフォルト設定されたポイントで定義されます。そのような関数が暗黙的に削除済みとして定義されている場合、プログラムは不正な形式です。[注:関数を最初の宣言の後にデフォルトとして宣言すると、進化するコードベースへの安定したバイナリインターフェースを有効にしながら、効率的な実行と簡潔な定義を提供できます。—エンドノート]

6 [例:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

—最後の例]

次に問題はもちろん、暗黙的に宣言できる関数と、それがいつ発生するかです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.