goto が危ないということが!「言葉」ではなく「心」で理解できた!

結論から言えば、変更が発生したときに処理の流れをつかみにくいのが良くありません。

for ( int index = 0; index < count; ++index ) {

    // .. 何かしらの処理

    if ( condition[index] ) {
        goto NEXT;
    }

    // .. 何かしらの処理

NEXT:
    // .. 結果の処理
}

さてこの goto の後ろで、とあるデータを参照する必要が出てきました。
以下のように修正します。

for ( int index = 0; index < count; ++index ) {

    // .. 何かしらの処理

    if ( condition[index] ) {
        goto NEXT;
    }

    // .. 何かしらの処理

    Data * pData = data[index];

    // .. pData を使う処理

NEXT:
    // .. 結果の処理
}

データはきちんと使う場所の近くで初期化しています。


そして、さらに結果の処理でもデータを使う必要が出てきました。

for ( int index = 0; index < count; ++index ) {

    // .. 何かしらの処理

    if ( condition[index] ) {
        goto NEXT;
    }

    // .. 何かしらの処理

    Data * pData = data[index];

    // .. pData を使う処理

NEXT:
    // .. 結果の処理
    
    // .. pData を使う結果の処理
}

goto によるジャンプが発生した場合、 pData を使う結果の処理の部分で
pData には何が入っているのか分かりません。

for ( int index = 0; index < count; ++index ) {

    // .. 何かしらの処理

    if ( ! condition[index] ) {
        // .. 何かしらの処理

        Data * pData = data[index];

        // .. pData を使う処理
    }
    // .. 結果の処理
    
    // .. pData を使う結果の処理
}

こうなっていればコンパイラが教えてくれたことでしょう。


実際に問題の発生したコードはループの本体が長くて goto もたくさんあったので
部分的な修正のときに周りのことが見えていなくて上記と同様の間違いをしてしまいました。


goto は Java のラベルつき break 文のエミュレート用途限定にしといたほうが
やっぱり無難かなーと思いました。