web-dev-qa-db-ja.com

C ++デフォルトデストラクタ

たとえばconstructorを宣言しない場合、コンパイラは引数も定義も(ボディ)も持たないdefault constructorを提供します。したがって、no action

現在destructorを宣言していない場合、コンパイラはdefault destructorを定義なし(ボディ)で提供するため、アクションなしと思います。

たとえば、オブジェクトを使い終わった場合、default destructorはオブジェクトが使用するメモリを再割り当て(解放)しませんか?そうでない場合、なぜそれを取得しているのですか?

そして、おそらく同じ質問がdefault constructorにも当てはまります。何もしない場合、なぜデフォルトで作成されるのですか?

ありがとう。

47
Simplicity

コンパイラによって生成されたデフォルトコンストラクターがアクションを実行しないと言うのは誤りです。これは、空の本体と空の初期化子リストを持つユーザー定義のコンストラクターと同等ですが、それはアクションをとらないという意味ではありません。以下がその機能です。

  1. 基本クラスのデフォルトコンストラクターを呼び出します。
  2. クラスがポリモーフィックである場合、vtableポインターを初期化します。
  3. それらを持つすべてのメンバーのデフォルトコンストラクターを呼び出します。いくつかのコンストラクターを持つメンバーが存在するが、デフォルトのコンストラクターがない場合、それはコンパイル時エラーです。

また、クラスがポリモーフィックではなく、基本クラスがなく、構築を必要とするメンバーがない場合にのみ、コンパイラー生成のデフォルトコンストラクターは何も行いません。しかし、それでも、他の回答で説明されている理由により、デフォルトのコンストラクターが必要になる場合があります。

同じことはデストラクタにも当てはまります-基本クラスのデストラクタとそれらを持っているすべてのメンバのデストラクタを呼び出すので、コンパイラが生成したデストラクタが何もしないのは一般的ではありません。

しかし、メモリ割り当ては実際にはこれとは関係ありません。メモリは、コンストラクタが呼び出される前に割り当てられ、最後のデストラクタが終了した後にのみ解放されます。

65
Sergei Tachenov

(パブリックにアクセス可能な)コンストラクターまたはデストラクターがない場合、クラスのオブジェクトをインスタンス化できないためです。考慮してください:

class A
{
private:
    A() {}
    ~A() {}
};

A a;  // Oh dear!  Compilation error

コンストラクターまたはデストラクターを明示的に宣言しない場合、コンパイラーはオブジェクトの作成を許可するものを提供する必要があります。

5

デフォルトのデストラクタは(デフォルトのコンストラクタのように)何もしません。

デストラクタが実際に何かを行う必要がある場合(たとえば、リソースを解放するなど)、自分で定義する必要があります。

通常は つの規則 に従う必要があります。プログラムがデストラクタで何かを行う必要がある場合(リソースの解放など)、コピーコンストラクタと代入演算子も提供する必要があります。 C++はそれらのデフォルトバージョンも提供します(これも何もしません)。

デフォルトのコンストラクタ/デストラクタ/割り当て演算子/コピーコンストラクタは、何もする必要のない単純なクラスを処理する場合に役立ちます。特別なケースはPODです。それらは(C++ 0xより前)明示的なコンストラクターまたはデストラクターを持つことさえできません。

4
peoro

デフォルトのコンストラクタとデストラクタは、クラスで特別なことを何もする必要がない場合の単なる商品であり、空のバージョンを手動で記述する必要はありません。これは、他のOO言語、たとえばJavaで共通です。メンバーのゼロ初期化で十分な場合、コンストラクターを提供する必要はありません。同時にCとの下位互換性のための要件です。Cにstructがある場合、コンストラクタまたはデストラクタはありません(Cにはこれらの概念はありません)。有効なコードであること。

別のオプションは、クラスにコンストラクターまたはデストラクターがないことを言語で宣言することでしたが、言語仕様全体では、一部のタイプにはコンストラクターとデストラクターがあり、他のタイプにはないという事実に対処する必要がありますより複雑で指定が難しい言語。暗黙的に定義されたバージョンを使用しても、動作は変わらず、仕様が容易になります。

このレベルでは、用語オーバーライドが基本クラスのメソッドに適用されているようなものです。基本クラスでは、オーバーライド何もしません。オーバーライドするものはありません!さらに、この言語では、ベースで宣言された仮想の非純粋メソッドはオーバーライドであると明示的に述べられています。これにより、特定のオーバーライドが存在しない場合、extre *またはベースメソッドの実装を追加せずに、メソッドがポインターまたは参照を介して呼び出されたときにfinal overriderが呼び出されることを仕様が単純に言うことができますその特定の階層のメソッド。

スマートポインターを使用する場合、メモリリークを回避するためにデフォルトのデストラクタ(Sergeyの答えを参照)が重要になる場合があります。次に例を示します。

#include <iostream>
#include <memory>

using namespace std;

class Foo {
public:
  Foo(int n = 0): n(n) { cout << "Foo(" << n << ")" << endl; }
  ~Foo() { cout << "~Foo(" << n << ")" << endl; }
private:
  int n;
};

// notes:
// * default destructor of Bar calls destructors of unique_ptr<Foo> foo
//  and of unique_ptr<Foo[]> foo3, which, in turn, delete the Foo objects
// * foo2's Foo object leaks
class Bar {
public:
  Bar(): foo(new Foo(1)), foo2(new Foo(2)), foo3(new Foo[2]) { }
private:
  unique_ptr<Foo> foo;
  Foo* foo2;
  unique_ptr<Foo[]> foo3;
};

int main() {
  Bar bar;
  cout << "in main()" << endl;
}

ここでは、foo2のみでリークが発生することを示す出力を示します。

Foo(1)
Foo(2)
Foo(0)
Foo(0)
in main()
~Foo(0)
~Foo(0)
~Foo(1)
2
Ulrich Stern

簡単な答えは、C++では、何もしなくても、すべてのオブジェクトにコンストラクタとデストラクタが必要だということです。したがって、バックグラウンドでそれらを作成するコンパイラーがこの要件を満たします。

より長い答えは、コンストラクターがクラスのメンバーの初期化に責任があるということです。デフォルトのコンストラクターは、すべてのメンバーのデフォルトの初期化を行います。 (これはPODタイプでは何の意味もありませんが、他のクラスはデフォルトのコンストラクターが呼び出されます。)

1
SoapBox

デフォルトのデストラクタは、クラスがどのメモリを「所有」してそれを解放できるかを知る方法がありません。

デフォルトのコンストラクター部分については、これについて Wikipediaの記事 を引用します...

C++では、デフォルトのコンストラクターは特定の状況で自動的に呼び出されるため重要です。

  • オブジェクト値が引数リストなしで宣言されている場合、例えばMyClass x ;;または、引数リストなしで動的に割り当てられます。新しいMyClass;デフォルトのコンストラクターを使用してオブジェクトを初期化します
  • オブジェクトの配列が宣言されるとき、例えばMyClass x [10] ;;または動的に割り当てられます。新しいMyClass [10];デフォルトのコンストラクタは、すべての要素を初期化するために使用されます
  • 派生クラスコンストラクターがその初期化子リストで基本クラスコンストラクターを明示的に呼び出さない場合、基本クラスの既定のコンストラクターが呼び出されます
  • クラスコンストラクターが初期化子リスト内のオブジェクト値フィールドのいずれかのコンストラクターを明示的に呼び出さない場合、フィールドのクラスのデフォルトコンストラクターが呼び出されます
  • 標準ライブラリでは、特定のコンテナは、値が明示的に指定されていない場合、デフォルトのコンストラクタを使用して値を「入力」します。 vector(10); 10個の要素でベクトルを初期化します。これらの要素には、デフォルトで構築されたタイプの値が設定されています。

上記の状況では、クラスにデフォルトコンストラクターがない場合はエラーになります。コンパイラーは暗黙的にデフォルトのコンストラクターを定義します

クラスに対してコンストラクタが明示的に定義されていない場合。この暗黙的に宣言されたデフォルトコンストラクターは、空白の本体で定義されたデフォルトコンストラクターと同等です。 (注:いくつかのコンストラクターが定義されているが、それらがすべてデフォルトでない場合、コンパイラーは暗黙的にデフォルトのコンストラクターを定義しません。これは、クラスにデフォルトのコンストラクターが存在しないことを意味します。)

0
Andrew White