2

デフォルトのクラスデストラクタは、呼び出されたときに実際に何かを実行するのだろうかと思っていました。

私はそれを調査していて、独自のデストラクタを呼び出す関数を使用してクラスを作成しても、何も実行されないことがわかりました(つまり、すべての変数は変更されず、インスタンスは引き続き存在し、使用可能です)。

これは、クラスデストラクタがすべてのクラスが持つ継承された仮想関数と見なすことができ、その再定義(ポインタなどを削除してメンバー変数をクリアする)が可能であることを意味しますが、再定義されていない場合は実行されます何もありませんか?

もしそうなら、デストラクタは本質的に「すべてのデータをクリアする」種類の関数として使用できず、コンピュータに新しいものを見つけさせるのではなく、動的にメモリが割り当てられた変数をクリアして再利用することにより、コードの一部をより効率的にすることができませんでしたヒープ上のメモリのブロック?

ありがとう。

4

4 に答える 4

2
  • デフォルトコンストラクターは、プリミティブ型(char、int、pointers)を含まない、すべてのメンバー変数のデフォルトコンストラクターを呼び出します。
  • デストラクタは明示的に呼び出すことができますが、オブジェクトの配置解除を意味するものではありません。オブジェクトがスタック上にある場合、オブジェクトはおそらく何もできません。
  • デストラクタはデフォルトでは仮想ではありませんが、クラスから継承する場合は実際に仮想である必要があります。
  • オブジェクトの割り当てが解除された場合(スコープ外になる、ヒープから削除された場合、またはオブジェクトを囲んでいるオブジェクトが何らかの方法で破棄された場合)、記述子が呼び出されます。
于 2013-02-16T12:24:49.543 に答える
2

私はそれを調査してきましたが、独自のデストラクタを呼び出す関数を使用してクラスを作成しても、何も実行されないことがわかりました(つまり、すべての変数は変更されず、インスタンスは引き続き存在し、使用可能です)。

このコードを考えてみましょう:

#include <iostream>

struct A
{
    ~A()
    {
        std::cout << "A::~A" << std::endl;
    }
};

struct B
{
    A a;
};

int main()
{
    B b;
    std::cout << "Calling b.~B()" << std::endl;
    b.~B();
    std::cout << "Done" << std::endl;
}

:が含まれているため、Bのデフォルトのデストラクタを呼び出すと、のデストラクタが呼び出されることがわかります。ABA

Calling b.~B()
A::~A
Done
A::~A

スコープから外れた場合にのみb、スタックが巻き戻され、合成されたものがB::~B()呼び出され、A::~A()メモリが解放される前に呼び出されます。

于 2013-02-16T12:34:48.563 に答える
1

Notinlistの答えに加えて:

デフォルトのコンストラクターは、基本クラスのコンストラクターを呼び出します。

もしそうなら、デストラクタは本質的に「すべてのデータをクリアする」種類の関数として使用できず、コンピュータに新しいものを見つけさせるのではなく、動的にメモリが割り当てられた変数をクリアして再利用することにより、コードの一部をより効率的にすることができませんでしたヒープ上のメモリのブロック?

あなたは一種のメモリプールを説明しています。必要に応じて、オブジェクトは、発明したプールシステムとの間でメモリバッファを取得および返すことができます。しかし、ほとんどの場合、割り当ては十分に高速でまれであるため、人々がこれを行うことは(もはや)一般的ではありません。まれであるとは言えませんが、パフォーマンスの低下に注意するためには、多くのことが発生している必要があります。

于 2013-02-16T12:30:51.470 に答える
1

デストラクタを手動で呼び出すことは、一般的に悪い考えです。デストラクタに関するC++FAQセクションには、これに関する多くの優れた情報があります。

オブジェクトを明示的に破棄したい場合は、追加のスコープを使用して、デストラクタを安全に呼び出すことができます(このFAQエントリを参照)。このメソッドは、破棄されたオブジェクトインスタンスを使用することも防ぎます。インスタンスは使用できるように見えるかもしれませんが、実際には使用できません。

クラスのインスタンスが所有するリソースのすべてではなく一部を解放することを意図している場合は、次の2つのことを試すことができます。

  • clear()クラスで(または同様の)メソッドを定義します。
  • clear()が呼び出された後、クラスの不変条件が維持されていることを確認してください。

デストラクタを手動で呼び出す最初のアプローチが機能したか、clear()上記の方法のようなことを選択したと仮定します。どちらの場合も、後で問題が発生する可能性があります。

C ++でよく理解され、よく実践されているリソース管理の方法は、Resource Acquisition Is Initializationです(RAIIと略されることがよくありますが、紛らわしい場合は名前を無視してください。概念は理解できます)。有用な情報については、このウィキペディアの記事またはこの回答を参照してください。

ただし、tl;drは次のとおりです。

  • リソースの存続期間は、常にオブジェクトの存続期間に関連付けられている必要があります。
  • オブジェクトの存続期間は、コンストラクターが完了すると始まります
  • オブジェクトの存続期間は、デストラクタが完了すると終了します。

このイディオムに従うと、通常、C++リソース管理の問題が発生する前に防止できます。

于 2013-02-16T12:51:58.590 に答える