質問

私は以前に尋ねました 質問 C ++で例外をチェーンする方法について、および回答の1つは、それがどのように行われるかについて気の利いたソリューションを提供しました。問題は、私がコードを理解していないことであり、コメントでこの種の議論をしようとすることはあまりにも面倒です。だから、新しい質問を完全に開始する方が良いと思いました。

コードは以下に含まれており、私が取得していない各セクションを明確にマークしました。私が理解していないことの説明は、コードの下に含まれています。コードはによって書かれました ポタトスワッター.


コード


struct exception_data { // abstract base class; may contain anything
    virtual ~exception_data() {}
};

struct chained_exception : std::exception {
    chained_exception( std::string const &s, exception_data *d = NULL )
        : data(d), descr(s) {
        try {
            link = new chained_exception;

            // ----------------------------------------------------------------
            //   How does this work (section 1)?
            throw;
            // ----------------------------------------------------------------

        } catch ( chained_exception &prev ) {
            // ----------------------------------------------------------------
            //   How does this work (section 2)?
            swap( *link, prev );
            // ----------------------------------------------------------------
        } // catch std::bad_alloc somehow...
    }

    friend void swap( chained_exception &lhs, chained_exception &rhs ) {
        std::swap( lhs.link, rhs.link );
        std::swap( lhs.data, rhs.data );
        swap( lhs.descr, rhs.descr );
    }

    virtual char const *what() const throw() { return descr.c_str(); }

    virtual ~chained_exception() throw() {
        // --------------------------------------------------------------------
        //   How does this work (section 3)?
        if ( link && link->link ) delete link; // do not delete terminator
        // --------------------------------------------------------------------
        delete data;
    }

    chained_exception *link; // always on heap
    exception_data *data; // always on heap
    std::string descr; // keeps data on heap

private:
    chained_exception() : link(), data() {}
    friend int main();
};

void f() {
    try {
        throw chained_exception( "humbug!" );
    } catch ( std::exception & ) {
        try {
            throw chained_exception( "bah" );
        } catch ( chained_exception &e ) {
            chained_exception *ep = &e;
            for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
                // Print ep->what() to std::cerr
            }
        }
    }

    try {
        throw chained_exception( "meh!" );
    } catch ( chained_exception &e ) {
        for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
            // Print ep->what() to std::cerr
        }
    }
}

int main() try {
    // ------------------------------------------------------------------------
    //   How does this work (section 4)?
    throw chained_exception(); // create dummy end-of-chain
    // ------------------------------------------------------------------------
} catch( chained_exception & ) {
    // body of main goes here
    f();
}

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

bah
humbug!
meh!

私が理解していないこと

  1. throw; 中身 try-ブロック: 私はこれを見たことがありません。私が思った唯一の場所 throw; 有効であることは内部にありました catch- キャッチされたものをrethrowにブロックします。それで、これは何をしますか?いくつかのデバッグは明らかに、スローされた例外が以前に投げられたものであることを示していますが、それはまったく異なる内部でした try-ブロック。実際、それは外にさえありました struct 宣言!

  2. フィールドを交換: なぜ必要とするのか スワップ 例外フィールド?ポインターをコピーするだけで十分ではないでしょうか?これは、フィールドがヒープから早期に削除されるのを指す構造を防ぐためですか?

  3. 小切手 link link'のリンク: 私はそれをチェックすることを理解できます link ではありません NULL (削除しても NULL ポインターには効果がありません)、なぜチェックする必要があるのか linkリンク?

  4. ダミー例外をスロー: なぜこのダミーが必要なのですか?投げられますが、落とされました。なぜこれをチェーンの終わりとして必要とするのですか?

役に立ちましたか?

解決

賢いコード - これについてのポタトスワッターへの称賛。しかし、私は最後のアイテムの周りに何らかの方法を見つけなければならないと思います。

  1. throw; アクティブな例外をrethrowsします。 aの場合にのみ有効です catch ブロックはスタック上にあります。私はそのちょっとしたことに出会った場所を思い出せませんが、おそらく他の質問の文脈ではそうでした。裸のスローは、現在の例外をキャッチすることで現在の例外にアクセスできます chained_exception コンストラクタ。言い換えると、 prev コンストラクターには、現在処理している例外への参照があります。

  2. あなたはここで正しいです。これにより、二重の削除が防止されます。

  3. センチネルの例外、投げ込まれたもの main, 、削除されないでください。この例外の識別属性は、それが link メンバーはです NULL.

  4. これは私が好きではないが、簡単な方法を考えることはできない部分です。唯一の目に見える chained_exception コンストラクターは、aの場合にのみ呼び出すことができます catch ブロックはアクティブです。 IIRC、アクティブなしで裸のスロー catch ブロックはノーです。したがって、回避策は投入することです main すべてのコードをに入れます catch ブロック。

ここで、この方法をマルチスレッドコードで試してみると、(4)を非常によく理解していることを確認してください。これをスレッドエントリポイントに複製する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top