なぜコンストラクタを明示的に削除するのですか?


93

いつ、なぜコンストラクタを明示的に削除したいのですか?理由がその使用を防ぐためであると仮定して、なぜそれを作ってみませんprivateか?

class Foo
{ 
  public: 
    Foo() = delete; 
};

14
それは一種のとうまく行く= defaultにもクラスがそれを使用することができ、私は個人的に見て好みではない、削除された機能の使用を。以上の機能はプライベートです。前者は「これは使用することを意図していない」と明確に述べています。それから何かが出てきた場合、それを使用できないクラスは実際に意味上の違いを作ります。
chris

15
正直なところ、人々は近い投票で攻撃的になり始めていると思います。これがどのように建設的でないかはわかりません。
Luchian Grigore

4
@LuchianGrigore:そうですね。私はなぜコミュニティが自分自身にはるかに厳格になったのかと思っていました。要点はわかりません。
Ed S.

11
私はめったにC ++ 11を使用しないので、これは、OPがおそらく実現するよりも、私にとってより有益です。のコンストラクタにタグを付けることができることさえ知りませんでしたdelete。質問とルチアンの答えはどちらも、建設的であると簡単に言えます。C ++ 11の細かい点に気を配っていない人は、すぐに両方から何かを得る必要があります。
WhozCraig

回答:


87

どうですか:

//deleted constructor
class Foo
{ 
  public: 
    Foo() = delete;     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //illegal
}

//private constructor
class Foo
{ 
  private: 
    Foo() {}     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //legal
}

それらは基本的に異なるものです。privateクラスのメンバーだけがそのメソッドを呼び出したり、その変数(またはもちろん友達)にアクセスしたりできることを示しています。この場合、staticそのクラスのメソッド(または他のメンバー)がprivateクラスのコンストラクターを呼び出すことは正当です。これは、削除されたコンストラクターには適用されません。

サンプルはこちら


3
Foo(int)を宣言する場合は、Foo()を宣言する必要はありません。Foo()は生成されないため、Foo fは無効です。したがって、あなたの例は削除されたコンストラクタの場合を示していません。自分の目で確かめ
マーク

1
@マークポイントを証明するために2つのコンストラクタを書きました。誰にでも分かりやすいように編集します。
Luchian Grigore

1
私は違いを理解していますが、一般的に、特にコンストラクターについては、deleteステートメントの付加価値を理解していません。結局のところ、本体なしでプライベートデフォルトコンストラクタを指定できました。次に、リンク中にのみ、コードも失敗します。ええと、削除が意図をより明確に伝えることがわかりますが、それはそれについてです。
マーク

11
@markはい、それはC ++ 98のやり方です。しかし、私見、意図を明確に伝えることは、プログラミング全般において実際に非常に重要なことです。この場合、一部の読者はプライベートの未定義のコンストラクターを見て、それが偶発的であると想定し、その定義を追加するだけです(特に、定義がデフォルトコンストラクターと同じくらい簡単な場合)(はい、コメントがあると役立ちますが、コンパイラーを優先します) -コメントの強制よりも強制)。意図をより明確にすることで、「未定義の参照」ではなく「明示的に削除された」というはるかに優れたエラーメッセージが表示されます。
mpark、2014年

2
正直なところ、これが主な質問にどのように答えるかはわかりません。タイトルの質問と投稿のOPの最初の質問は次のとおりです。いつ/なぜコンストラクタを明示的に削除したいですか?
Alexander Bolinsky 16年

11

なぜコンストラクタを明示的に削除するのですか?

別の理由:クラスがイニシャライザで呼び出されることを保証したい場合
に使用deleteします。ランタイムチェックなしでこれを実現する非常にエレガントな方法だと思います。

C ++コンパイラはこのチェックを行います。

class Foo
{
   public:
       Foo() = delete;
       Foo(int bar) : m_bar(bar) {};
   private:
       int m_bar;
}

これ- 非常に簡略化された -コードは、次のようなインスタンス化がないことを保証します。Foo foo;


12
削除された宣言はここでは不要です。ユーザー指定のコンストラクターによって自動的に削除されます
Mike Lui

5
@MikeLuiによるコメントを明確にするために、削除された宣言はコンパイラーにとって不要です。他のプログラマに意図宣言するために、このようなコードを含める必要がある場合は数多くあります
Jeff G

意図を宣言するとともに、削除の理由をパブリックインターフェイスに文書化する明白な場所を作成します。さらに、コンパイラーエラーは「削除された関数の使用」のような短いものになります。場合はFoo、多くのコンストラクタだけではない、デフォルトのものを持っていたし、Foo foo;それが一致しなかったすべての暗黙のうちに、定義された保護およびプライベートコンストラクタをリストはるかに長いエラーが発生します。
シグマ

「= delete」キーワードを使用したコンストラクターの宣言を含む追加の行が、「デフォルトコンストラクターなし」という意図をどのように宣言するのかがわかりません。サンプル:コードで変数 "a"を宣言したくない-"// int a; //変数aを定義する必要がない"またはコードでこの変数について何も記述しないほうがよいのは何ですか?
エズ

2

LLVMのソースコード(たとえばAlignOf.h)で「削除済み」として宣言されたデフォルトのctorに遭遇しました。関連するクラステンプレートは通常、「llvm :: detail」と呼ばれる特別な名前空間にあります。そこでの全体的な目的は、彼らがそのクラスをヘルパークラスとしてのみ見なすことだったと思います。彼らはそれらをインスタンス化するつもりはありませんでした。コンパイル時に実行されるいくつかのメタプログラミングトリックを備えた他のクラステンプレートのコンテキスト内でのみ使用します。

例えば。sizeof(。)演算子のパラメーターとしてAlignOfと呼ばれる別のクラステンプレート内でのみ使用されるこのAlignmentCalcImplクラステンプレートがあります。その式はコンパイル時に評価できます。テンプレートをインスタンス化する必要はありません->それで、この意図を表すためにデフォルトのctor削除を宣言しないでください。

しかし、それは私の仮定にすぎません。

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