4

デストラクタでexit()を呼び出している次のプログラムがあります。main()内にサンプル型のオブジェクトを作成すると、デストラクタが1回呼び出され、プログラムは正常に終了します。しかし、サンプル型のグローバルオブジェクトを作成すると、「Destructing..」が無限に出力されます。誰か説明してもらえますか?

#include "iostream"
#include "conio.h"

using namespace std;

class sample
{
      public:
     ~sample() {
                    cout <<"Destructing.."<<endl;
                    exit(0);
                }
};

sample obj;

int main()
{
 getch();   
}
4

3 に答える 3

2

何が起こっているのかというと、このexit()関数は、すべてのグローバルオブジェクトのデストラクタを呼び出すようにプログラムを取得しています。また、クラスのデストラクタがオブジェクトを呼び出した時点ではexit(1);、オブジェクトはまだ破壊されているとは見なされていないため、デストラクタが再度呼び出され、無限ループが発生します。

あなたはこれで逃げることができます:

class sample {
    bool exiting;
public:
    sample() { exiting = false; }
    ~sample() {
        cout << "Destructing.." << endl;
        if(exiting) return;
        exiting = true;
        exit(0);
    }
};

しかし、デストラクタを呼び出すexit()ことは悪い考えです。これらの選択肢の1つを検討してください。

  • 終了するための別の通常の(非デストラクタ)メソッドを作成します
  • 「プログラム」が終了するまで実行される関数を作成し、main()
  • abort()代わりに使用exit()してください(これについて言及してくれたgoldilocksに感謝します)。 が呼び出さabort()れたときと戻ったときに通常実行されるすべてのクリーンアップをバイパスします。ただし、プログラム内の特定のクリーンアップ操作が非常に重要になる可能性があるため、これも必ずしも良い考えではありません。 クリーンアップをバイパスすることが保証されているほどすでにひどいエラーのみを対象としています。exit()main()abort()

以前に例外を提案しましたが、内部のデストラクタから例外をスローすることを思い出し、考えを変えました。これが理由です。

また、動作に一貫性がないことにも注意してください。一部のコンパイラ/環境では無限ループが発生しますが、そうでないものもあります。デストラクタのどの時点でオブジェクトが破壊されたと見なされるかが決まります。標準はこれをカバーしていないか、この場合の動作は未定義であると言っていると思います。

于 2012-04-30T06:07:27.300 に答える
2

私は、デストラクタでそれを行うことは悪い設計の兆候であるというMichealSladeに同意します。ただし、そうする正当な理由があると思われる場合(たとえば、開発の問題)、abort()の代わりにを使用してexit(0)ください。これにより、これ以上デストラクタが呼び出されるのを防ぎ、再帰ループから抜け出すことができます。

于 2012-04-30T06:10:20.407 に答える
1

破壊するデストラクタがexitを呼び出し、それがexitを呼び出す破壊デストラクタを呼び出し、次にexitを呼び出します...(はい、非常に長い間続きます)。

于 2012-04-30T06:03:19.617 に答える