1

C ++クラスのコンストラクター関数を再帰的に使用して、「trauthテーブル」を出力して遊んでいました。「デストラクタを再帰的に使用しないのはなぜですか」と判断するまでは、すべてが正常であるように見えました。デストラクタを使用して「trauthテーブル」の印刷も実装したとき、コントロールがコンストラクタへのrecurisve呼び出しから戻るたびにデストラクタが呼び出されていることに気付きました。

出力スニペット

Calling hello_world class constructor...
000
A destructor call within initialization has been terminated
001
A destructor call within initialization has been terminated
A destructor call within initialization has been terminated
010
...
...

クラス

#define MAX 3
class hello_world
{
    char *const buf;
    int stack_ptr, destructor_calls;
    bool init;
public:

    // The recursive constructor

    hello_world(char *const &str, int i = 0)
        : buf(str), stack_ptr(0), init(false), destructor_calls(0)
    {
        if (i == MAX)
        {
            buf[i] = '\0';
            cout << buf << endl;
        }
        else
        {
            buf[i] = '0';
            hello_world::hello_world(str, i + 1);
            buf[i] = '1';
            hello_world::hello_world(str, i + 1);
        }
    }

    // The recusive destructor

    ~hello_world()
    {
        ++destructor_calls;
        if (!init) { cerr << "A destructor call within initialization has been terminated" << endl; return; }

        int i = stack_ptr;
        if (i == MAX)
        {
            buf[i] = '\0';
            cout << buf << endl;
        }
        else
        {
            buf[i] = '0';
            ++stack_ptr; // since a destructor cannot take parameters
            hello_world::~hello_world();
            --stack_ptr;
            buf[i] = '1';
            ++stack_ptr;
            hello_world::~hello_world();
            --stack_ptr;

            // Printing total number of calls at final call
            if (i == 0) cout << endl << "\"destrucotr_calls\" = " <<
 destructor_calls << endl;
        }
    }

    void unlock()
    {
        init = true;
    }
}; // end of class hello_world

デストラクタはパラメータを持つことができないため、現在のパラメータint hello_world::stack_ptr数を格納するためにを使用しています。i

私の質問は、コントロールがコンストラクターに再帰呼び出しを残すたびに、なぜデストラクタが呼び出されるのかということです。

これが私のmain()です:

void main()
{
    char buf[MAX + 1];
    cout << "Calling hello_world class constructor..." << endl;
    hello_world h(buf);
    h.unlock();
    cout << "Calling hello_world class destructor..." << endl;
}

VS2010を使用しています。ここで、完全なコードとその出力を表示できます

追加:を使用して呼び出しているデストラクタの総数をカウントしようとしていint hello_world::destructor_callsます。trauthテーブルアルゴリズムの印刷には2 * (2^MAX) - 1呼び出しが必要であり、最終的destructor_callsにはこの値と正確に等しいことがわかりました。しかし、出力された文"A destructor call within initialization has been terminated"を数えると、14回出力されていることがわかります。したがって、14(初期化内の呼び出し)+ 15(trauthテーブルの印刷の自然な呼び出し)は29にdestructor_calls等しく、15のみに等しい必要があります(初期化時にデストラクタが呼び出されていないかのように!!)

4

2 に答える 2

3

再帰コンストラクタのようなものはありません。再帰のように見えるのは、実際には新しい一時オブジェクトを作成することです。

デストラクタを直接呼び出すことは可能ですが、同じオブジェクトに対してデストラクタを 2 回呼び出すと、未定義の動作が発生するため、再帰的に呼び出すことはできません。

コンストラクターまたはデストラクター内で別のメンバー関数を呼び出す必要があります。次に、これらの他の関数を再帰的にすることができます:

class A {
  A()  { construct(); }
  ~A() { destruct(); }
  void construct(int i=0) { ... construct(i+1); ... }
  void destruct(int i=MAX) { ... destruct(i-1); ... }
};
于 2012-09-09T14:31:15.197 に答える
2

あなたは火遊び...

hello_world::hello_world(str, i + 1);

一時オブジェクトを作成してから破棄します...

于 2012-09-09T14:31:59.793 に答える