8

次のコードで、デストラクタにいくつか問題があります。

#include <stdlib.h>
#include <cstdio>

class Foo2
{
    public:
        Foo2() { printf("foo2 const\n"); }

        ~Foo2()
        {
            printf("foo2 dest\n"); //  <--- wasn't called for bionic libc
        }
};

static Foo2& GetFoo2()
{
    static Foo2 foo2;
    printf ("return foo2\n");
    return foo2;
}

class Foo1
{
    public:
        Foo1() { printf("foo1 const\n"); }

        ~Foo1()
        {
            printf("foo1 dest\n");
            GetFoo2();
        }
};

int main( int argc, const char* argv[] )
{
        printf("main 1 \n");
        static Foo1 anotherFoo;
        printf("main 2 \n");
}

なぜfoo2のデストラクタが呼び出されなかっbionicたのglibcですか?


バイオニックの出力を 編集:

main 1  
foo1 const  
main 2  
foo1 dest  
foo2 const  
return foo2  

デバッグ情報:

(gdb) break 22
Breakpoint 1 at 0x8048858: file test.C, line 22.
(gdb) info breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048858 in Foo2::~Foo2() at test.C:22
(gdb) cont
[    exited with code 0]
4

4 に答える 4

6

あなたのコードには未定義の動作があると思いますが、標準では明確ではありません (または、標準で見つけることができません)。コードは、静的オブジェクトのデストラクタで新しい静的オブジェクトを構築します。標準はこのケースに対応していませんが、次のようになります。

  1. デストラクタは構築の逆の順序で呼び出さなければならないと言っています。あなたの場合、これは、静的オブジェクトGetFoo2が構築される前に破棄されなければならないことを意味します。これは自己矛盾です。

  2. §3.6/3 のテキストは、 に登録されたデストラクタと関数の順序付けについて説明していatexitます。要件は、それぞれに同じ登録メカニズムを使用する必要があるというものです。また、atexit一度呼び出したexit(または から戻った main) 呼び出しは、未定義の動作です。

  3. §3.6/2 もあり、「関数に、破棄された静的またはスレッド ストレージ期間のブロック スコープ オブジェクトが含まれていて、静的またはスレッド ストレージ期間を持つオブジェクトの破棄中に関数が呼び出された場合、プログラムは制御フローが以前に破棄されたブロックスコープ オブジェクトの定義を通過する場合、未定義の動作をします。」この文は、すでに破壊されたオブジェクトについて述べていますが、「まだ構築されていない」オブジェクトが存在しないのは単なる見落としであると考えるのは想像に難くありません。

最後に、上記の最初のポイントは、意図に関して決定的であると言えます。§1.3.24 には、「この国際標準が動作の明示的な定義を省略している場合、またはプログラムが誤った構造または誤ったデータを使用している場合、未定義の動作が予想される場合がある」という注記があります (規範的ではありませんが、意図を示しています)。この場合、必要な動作の唯一の説明は不可能であり (オブジェクトが構築される前にオブジェクトを破壊することはできないため)、標準はこれをどのように解決すべきかについて何も述べていません。

于 2013-01-11T12:53:28.753 に答える
5

このコードに表示されるすべてのインスタンスは静的です。

結果として、それらのデストラクタは、main が終了した後、実行可能ファイルの最後で呼び出されます。

デストラクタが呼び出されなかった場合、それはバグです。

于 2013-01-11T12:18:45.840 に答える
4

C++11 3.6.3/1: 初期化されたオブジェクトのデストラクタ [...] 静的ストレージ期間を持つデストラクタは、から戻った結果として呼び出されますmain

プログラムが から戻った時点でmainanotherFooは初期化されています。の破棄中のfoo2最初の呼び出しまで初期化されないため、そうではありません。したがって、ルールを厳密に解釈すると、そのデストラクタを呼び出すべきではないことが暗示されます。GetFoo2anotherFoo

于 2013-01-11T12:51:13.203 に答える
4

プログラムが存在する場合、静的オブジェクトは破棄されます。にブレークポイントを配置すると~Foo2()、それが表示されるか、ログをファイルに書き込むと診断に役立ちます。本当に呼び出されない場合は、コンパイラのバグです。

ここに画像の説明を入力

質問に答えるために写真をアップロードするのも楽しいです。

于 2013-01-11T12:26:37.050 に答える