9

これはより適切な質問だと思ったので、タイトルを少し変更しました。

リファクタリングしますか (goto の正当な使用のようです) ? 次のコードをどのようにリファクタリングして go to ステートメントを削除しますか?

if (data.device) {
    try {
        ...
    }
    catch(const std::exception&) { goto done; }
    ... // more things which should not be caught
done: ;
}

完全なステートメント

#ifdef HAVE_GPU
            // attempt to use GPU device
            if (data.device) {
                try {
                    Integral::Gpu eri(S, R, Q, block.shell());
                    eri(basis.centers(), quartets, data.device);
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) { goto done; }
                data.device += size;
                host_index.extend(block_index);
                block_index.data.clear();
            done: ;
            }
#endif

ありがとうございました

ほとんどの好みを見た後、フラグで行くことにしましたが、ヨーク氏のコメントで。

みんなありがとう

4

14 に答える 14

15
if (data.device)
{
    bool status = true;

    try
    {
        ...
    }
    catch(std::exception)
    {
        status = false;
    }

    if (status)
    {
    ... // more things which should not be caught
    }
}
于 2010-07-27T17:05:22.140 に答える
8

最初に: goto 自体は悪ではありません。コードに「goto」という文字が含まれていないという純粋な目的のためのリファクタリングはナンセンスです。goto よりもきれいに同じことを行うものにリファクタリングすることは問題ありません。悪い設計をより良いものに変更し、goto やその代替を必要としないことも問題ありません。

そうは言っても、あなたのコードは最終的に発明されたものとまったく同じように見えると思います。残念なことに、C++ にはこのようなものはありません。

于 2010-07-27T17:09:51.607 に答える
7

例外をキャッチして、条件付きブロックの外部で処理できる特定の例外を再スローできます。

// obviously you would want to name this appropriately...
struct specific_exception : std::exception { };

try {
    if (data.device) {
        try {
            // ...
        }
        catch(const std::exception&) { 
            throw specific_exception(); 
        }

        // ... more things which should not be caught ...
    }
}
catch (const specific_exception&) { 
    // handle exception
}
于 2010-07-27T17:06:29.017 に答える
4

余分なコードをtryブロック内に移動してみませんか?:

#ifdef HAVE_GPU
            // attempt to use GPU device
            if (data.device) {
                try {
                    Integral::Gpu eri(S, R, Q, block.shell());
                    eri(basis.centers(), quartets, data.device);
                    data.device += size;
                    host_index.extend(block_index);
                    block_index.data.clear();
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) { /* handle your exception */; }
            }
#endif
于 2010-07-27T17:21:47.857 に答える
4

これの変種があなたのために働くかもしれないと思います。

// attempt to use GPU device
if (data.device)
{
    try
    {
        Integral::Gpu eri(S, R, Q, block.shell());
        eri(basis.centers(), quartets, data.device);

        data.device += size;
        host_index.extend(block_index);
        block_index.data.clear();
    }
    catch (const std::bad_alloc&)
    {
        // this failure was not because 
        // of the GPU, let it propagate
        throw;
    }
    catch(...)
    {
        // handle any other exceptions by
        // knowing it was the GPU and we 
        // can fall back onto the CPU.
    }
}

// do CPU

GPU ライブラリを編集して、すべての GPU 例外に のようなベースを与えることができればgpu_exception、コードははるかに単純になります。

// attempt to use GPU device
if (data.device)
{
    try
    {
        Integral::Gpu eri(S, R, Q, block.shell());
        eri(basis.centers(), quartets, data.device);

        data.device += size;
        host_index.extend(block_index);
        block_index.data.clear();
    }
    catch (const gpu_exception&)
    {
        // handle GPU exceptions by
        // doing nothing and falling
        // back onto the CPU.
    }

    // all other exceptions, not being 
    // GPU caused, may propagate normally
}

// do CPU

これらのいずれも機能しない場合、次善の策はスティーブの答えだと思います。

于 2010-07-27T17:27:11.480 に答える
4

フラグの使用方法が少し異なります。Amardeepのものよりきれいだと思います。

最後のことが機能したかどうかを示すフラグよりも、例外を伝播するかどうかを示すフラグを使用したいのですが、例外の全体的なポイントは、最後のことが機能したかどうかのチェックを回避することです-アイデアはコードを書くことですここまで進めば、すべてがうまくいき、続行できます。

#ifdef HAVE_GPU
    // attempt to use GPU device
    if (data.device) {
        bool dont_catch = false;
        try {
            ...
            dont_catch = true;
            ... // more things which should not be caught
        } catch (...) {
            if (dont_catch) throw;
        }
    }
#endif
于 2010-07-27T17:30:50.997 に答える
3
if (data.device) {
    bool ok = true;
    try {
        ...
    }
    catch(std::exception) { ok = false; }

    if(ok) {
        ... // more things which should not be caught
    }
}
于 2010-07-27T17:06:05.900 に答える
2

ifの外で例外をキャッチできませんか?

于 2010-07-27T17:03:51.753 に答える
2

いくつかの条件に基づいて終了する必要があるコードがたくさんある場合、私が好む構成は、「do {} while(0)」ループを使用し、適切な場合は「ブレーク」することです。何が壊れたのかわかりません。しかし、キャッチで行います。「break」が機能しない場合は、「goto」が最善の策かもしれません。

于 2010-07-27T17:16:55.997 に答える
2

私は何かが欠けていますか、それともブロック内のcatchdone:ラベルの間の部分を移動することと同等ではないでしょうか?try

#ifdef HAVE_GPU
            // attempt to use GPU device
            if (data.device) {
                try {
                    Integral::Gpu eri(S, R, Q, block.shell());
                    eri(basis.centers(), quartets, data.device);
                    data.device += size;
                    host_index.extend(block_index);
                    block_index.data.clear();
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) {}
            }
#endif
于 2010-07-27T17:32:18.783 に答える
1

それを独自の関数/メソッド(その後のすべてを含む)に分割し、returnキーワードを使用するだけです。すべての変数にデストラクタがあり、スタックに割り当てられている(または、やむを得ない場合はスマートポインターである)限り、問題はありません。私は継続的なフラグチェックではなく、早期終了関数/メソッドの大ファンです。

例えば:

void myFunc()
{
    String mystr("heya");
    try
    {
        couldThrow(mystr);
    }
    catch(MyException& ex)
    {
        return; // String mystr is freed upon returning
    }

    // Only execute here if no exceptions above
    doStuff();
}

このように、間違いは難しいです

于 2010-07-27T17:36:26.147 に答える
1
catch(std::exception) { return; }

それでうまくいくはずです。もちろん、私はそれdoneが実際に関数の終わりにあると仮定しています。

例外が発生したときに追加のコードを実行する必要がある場合は、ステータスを返すか、より適切な抽象化レベルの例外をスローします(Jamesの回答を参照)。

私は次のようなものを想像しています:

doStuff(...) {
    bool gpuSuccess = doGPUStuff(...);
    if (!gpuSuccess) {
        doCPUStuff(...);
    }
}
于 2010-07-27T17:19:44.470 に答える
1

今日 goto が嫌われている理由は、代わりに「関数」と呼ばれる凝ったものがあるからです。GPU コードを独自の関数でラップし、失敗した場合に早期に返すことができます。

次に、元の関数からそれを呼び出します。

おそらくいくつかの変数 ( と のように見える) を共有する必要があるため、dataそれらをクラスに入れ、2 つの関数をそのメンバーにしますhost_indexblock_index

void RunOnGpu(){
        // attempt to use GPU device
        if (data.device) {
            try {
                Integral::Gpu eri(S, R, Q, block.shell());
                eri(basis.centers(), quartets, data.device);
            }
            // if GPU fails, propagate to cpu
            catch(std::exception) { return; }
            data.device += size;
            host_index.extend(block_index);
            block_index.data.clear();     
}
void DoStuff() {
#ifdef HAVE_GPU
    RunOnGpu();
#endif
}
于 2010-07-27T19:39:57.287 に答える
1

フラグを使用して条件文を追加するだけではどうですか?

int caught = 0;
if (data.device) {
    try {
        /* ... */
    } catch (std::exception e) { caught = 1; }
    if (!caught) {
        // more stuff here
    }
    // done: ...
}
于 2010-07-27T17:07:32.887 に答える