16

RAIIの振る舞いがgotoの使用とどのようにかみ合うかについての純粋な好奇心(誰もこのようなコードを書くべきではないからです!)以外の目的ではないのだろうかと思います(素敵なアイデアではありません)。

class Two
{
public:
    ~Two()
    {
        printf("2,");
    }
};

class Ghost
{
public:
    ~Ghost()
    {
        printf(" BOO! ");
    }
};

void foo()
{
    {
        Two t;
        printf("1,");
        goto JUMP;
    }
    Ghost g;
JUMP:
    printf("3");
}

int main()
{
        foo();
}

Visual Studio 2005で次のコードを実行すると、次の出力が得られます。

1,2,3 BOO!

しかし、私は想像し、推測し、「BOO!」を望んでいました。Ghostがインスタンス化されるべきではなかったため、実際には表示されません(IMHO、このコードの実際の予想される動作がわからないため)。

どうしたの?


Ghostの明示的なコンストラクターをインスタンス化すると、コードがコンパイルされないことに気づきました...

class Ghost
{
public:
    Ghost()
    {
        printf(" HAHAHA! ");
    }
    ~Ghost()
    {
        printf(" BOO! ");
    }
};

ああ、謎...

4

3 に答える 3

25

標準では、これについて明示的に説明しています-例を示します。6.7 / 3「宣言ステートメント」(私が強調したもの):

自動保存期間のある変数は、宣言ステートメントが実行されるたびに初期化されます。 ブロックで宣言された自動保存期間を持つ変数は、ブロックの終了時に破棄されます

ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法ではできません。自動保存期間のあるローカル変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数がPODタイプであり、初期化子なしで宣言されていない限り、形式が正しくありません。

[例:

void f()
{
    //...
    goto lx;  //ill-formed: jump into scope of a
    //...

ly:
    X a = 1;
    //...

lx:
    goto ly;  //OK, jump implies destructor
              //call for a, followed by construction
              //again immediately following label ly
}

-例を終了]

したがって、MSVCの動作は標準に準拠していないように見えます-PODタイプではないため、ステートメントがそれを飛び越えるようにコーディングされてGhostいる場合、コンパイラはエラーを発行する必要があります。goto

私が試した他のいくつかのコンパイラ(GCCとDigital Mars)はエラーを発行します。Comeauは警告を発行します(ただし、公平を期すために、ComeauのビルドスクリプトはMSVCとの互換性が高くなるように構成されているため、意図的にMicrosoftのリードに従っている可能性があります)。

于 2010-03-09T05:10:58.967 に答える
0

後藤は放射性ではありません。goto による離脱は、例外による離脱とほとんど変わりません。goto による入力は、言語の制限ではなく、利便性によって決定されるべきです。ゴーストが構築されているかどうかがわからないということは、それを行わない正当な理由です。

コンストラクタの前にジャンプします。いくつかのオブジェクトが既に構築された後に飛び込みたい場合は、それを新しいスコープで囲むか、そうでなければ自分でその寿命を解決してください。

于 2010-03-09T05:37:34.640 に答える