23

次のコードを使用して、C++ でデストラクタを試していました。

#include <iostream>

struct temp
{
    ~temp() { std::cout << "Hello!" << std::endl; }
};

int main()
{
    temp t;
    t.~temp();
}

「こんにちは!」とわかります。2回印刷されています。デストラクタを呼び出してオブジェクトを解放するべきではなく、スコープ外になったときにデストラクタを再度呼び出すべきではありませんか? それとも何か他の概念がありますか?

(実際にこれを行うつもりはありません。ここで何が起こっているのかを理解しようとしているだけです。)

4

10 に答える 10

43

あなたがそうするように言ったから、それは起こるのです。自動変数のデストラクタは、変数がスコープ外になると常に呼び出されます。あなたもそれを呼んだ。それは合計2回の呼び出しです。

通常の実行では追跡する必要がないため、オブジェクトのデストラクタを呼び出しても、C++ に再度呼び出さないように通知することはありません。

解決策は、デストラクタを手動で呼び出さないことです。

于 2012-08-09T13:11:58.690 に答える
20

デストラクタを呼び出しても、オブジェクトは解放されません。

デストラクタはオブジェクトの内部をクリーンアップするために存在し、デストラクタが終了するとオブジェクト自体が解放されます。

オブジェクトに対して delete を 2 回呼び出すのと同じように行うのはエラーですが、そうするのはエラーです。

デストラクタを手動で呼び出したい場合はごくわずかであり、これはその 1 つではありません。これは、placement new を使用して手動でメモリ位置にオブジェクトを構築し、メモリを解放せずにオブジェクトを破棄できるようにする必要がある場合に実際に存在します。

于 2012-08-09T13:13:43.020 に答える
3

「こんにちは!」とわかります。2回印刷されています。デストラクタを呼び出してオブジェクトを解放するべきではなく、スコープ外になったときにデストラクタを再度呼び出すべきではありません。それとも他の概念がありますか?

そのとおりです。

実際にこれを行うつもりはありません。ここで何が起こっているのかを理解しようとしています。

デストラクタを呼び出して、オブジェクトを破棄する準備をしました。ただし、これは、オブジェクトが実際に割り当て解除される前に、オブジェクトがスコープ外になったときにも自動的に行われます。

理解しておくべきことは次のとおりです。意味をなさないことをすると、悪いことが起こります。ですから意味のないことはしないでください。デストラクタを手動で呼び出すと、デストラクタが実行されます。デストラクタが実際に効果のあることをしない限り、それは他のものには何の影響もありません。

于 2012-08-09T13:18:44.477 に答える
1

デストラクタは、この場合のようにオブジェクトがスタック内にある場合にオブジェクトがスコープ外になったときに呼び出されるか、オブジェクトが最初に new 演算子でヒープ上に作成されたときに delete で明示的に破棄されたときに呼び出されることを意図しています。

デストラクタが手動で呼び出されたかどうかをコンパイラまたはランタイム システムが追跡する方法はありません。また、デストラクタを呼び出すことは非常に悪い習慣です。

オブジェクトが削除される前に (オブジェクトがメモリから削除されたり、スタックから削除されたりする以外に) 手動でクリーニングを行いたい場合は、次のようにすることができます。

ここでは、オブジェクトが削除される前であっても、クライアントが手動でクリーンアップできるようにします。しかし、それに加えて、クライアントが掃除を怠った場合は、物を掃除します。

class A
{
public:
    A() : _closed(false)
    {}

    ~A()
    {
        close();
    }

    void close()
    {
        if (! _closed()) {
            // close file handles etc.
        }
    }

private:
    bool _closed
}
于 2012-08-09T13:15:33.310 に答える
1

デストラクタは、オブジェクトの「破壊者」ではありません。ごく普通の関数ですが、破壊の直前に言語によって自動的に呼び出されます。

正式名称はデストラクタですが、「Before-Destruction」関数と呼んだ方が分かりやすいかもしれません。

于 2012-08-09T21:00:55.030 に答える
1

デストラクタを呼び出すことは可能ですが、呼び出す必要はありません。オブジェクトが使用されなくなった場合、コンパイラはデストラクタを暗黙的に実行する必要があります。オブジェクトが作成されると、コンストラクターがクラス メンバーの特定の初期化された値で宣言されている場合、そのオブジェクトに対してコンストラクターが使用されます。オブジェクトが不要になると、デストラクタが実行され、メンバー変数の宣言とその値が削除されます。これは、C++ などの自動ガベージ コレクションを使用しない言語で最も役立ちます。

于 2012-08-13T12:52:00.610 に答える
1

デストラクタを呼び出すだけで、実際にはメモリを解放しません (静的に割り当てられます)。new を使用してから delete を使用すると、デストラクタは 1 回だけ呼び出されます。

于 2012-08-09T13:18:52.257 に答える
0

デストラクタを明示的に呼び出すのではなく、変数がスコープ外になると自動的に呼び出されます (ここではreturn 0;ステートメントの後)。これが 2 回呼び出される理由です。あなたが呼び出すと、システムが呼び出します。

このクラスのインスタンスを自分で明示的に削除できるようにしたい場合は、動的に割り当てる必要があります。

temp *t = new temp;     
// do stuff with t...
delete t;    // do not forget this, or the constructor is not being called at all
于 2012-08-09T13:14:17.703 に答える
0

クラスのデストラクタを呼び出すことができます:

  1. 明示的に

    クラスのオブジェクトを使用してデストラクタが明示的に呼び出される場合、クラスの別のメンバー関数を呼び出すのと同じ方法です。

  2. 暗黙的に

    クラスのオブジェクトがスコープ外になった場合、または new 演算子を使用して作成されたオブジェクトが delete 演算子を使用して破棄された場合。

サンプル プログラムでは、両方を行います。

int main()
{
  temp t;

  t.~temp(); //1. Calling destructor explictly using the object `t`

  return 0;
} // 2. object `t` goes out of scope. So destructor invoked implictly

これが、デストラクタが 2 回呼び出される理由です。

お察しのとおり、デストラクタはコンストラクタによって作成されたリソースを破棄します。そのため、デストラクタを明示的に呼び出すべきではありません。すでに破棄されたリソースが破棄され、致命的となる可能性があるためです。

于 2012-08-13T13:37:44.780 に答える
0

実際にデコンストラクターを呼び出すべきではありません。これは、ランタイム サポートによって呼び出されます。したがって、一度呼び出すと、ランタイム サポートが 2 回目に呼び出すことになります。

以下は、デストラクタに関する考慮事項です。

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr380.htm

デコンストラクターを明示的に呼び出すことはできますが、お勧めしません。通常、デコンストラクターは暗黙的に呼び出されます。

于 2012-08-09T13:13:54.867 に答える