NOEMBLEM/エンブレムが設定されていません。

メールの詳細(トピック表示)

[Q] 複数の例外を捕まえるには?

投稿者:επιστημηさん  2014/09/10 13:36  MLNo.14099   [メール表示]

επιστημη@困ったときのcppll頼み です。

複数の例外がthrowされるシチュエーションがありまして。
# マルチスレッドなんかだと同時にthrowされるかも、みたいな。

例外をthrowする側では std::exception_ptr の集合: exception_list を
throwします。exception_list には begin()/end() があるので内包する
exception_ptrを列挙できます。そうすると、

try {
try {
ここで exception_list がthrowされる
} catch ( exception_list& errors ) {
for ( exception_ptr eptr : errors ) {
std::rethrow_exception(eptr); // [*] 再throw
}
} catch ( そのほか ) {
...
}
} catch ( foo_error& xxx ) {
// [*]でthrowされたのを捕まえる-1
} catch ( bar_error& yyy ) {
// [*]でthrowされたのを捕まえる-2
}

こんなカンジかしら。
...んでもこれだと exception_list のイッコ目が catch
されたらcatch節を抜けちゃうですよね?

複数の例外を捕まえるのって、どうやるんでしょ?


このエントリーをはてなブックマークに追加


  • MLNo.14100   "MITSUNARI Shigeo"さん  (0) 2014/09/10 14:17  [メール表示する]
    光成です。

    >例外をthrowする側では std::exception_ptr の集合: exception_list を
    >throwします。exception_list には begin()/end() があるので内包する
    >exception_ptrを列挙できます。そうすると、
    >
    >try {
    > try {
    > ここで exception_list がthrowされる
    > } catch ( exception_list& errors ) {
    > for ( exception_ptr eptr : errors ) {
    > std::rethrow_exception(eptr); // [*] 再throw
    > }
    > } catch ( そのほか ) {
    > ...
    > }
    >} catch ( foo_error& xxx ) {
    > // [*]でthrowされたのを捕まえる-1
    >} catch ( bar_error& yyy ) {
    > // [*]でthrowされたのを捕まえる-2
    >}
    >
    >こんなカンジかしら。
    >...んでもこれだと exception_list のイッコ目が catch
    >されたらcatch節を抜けちゃうですよね?
    >
    >複数の例外を捕まえるのって、どうやるんでしょ?

    質問の意図をとり間違えているのかもしれませんが、for()の部分で
    catchしたら駄目なんでしょうか。

    #include <exception>
    #include <stdio.h>
    #include <vector>
    #include <stdexcept>

    typedef std::vector<std::exception_ptr> exception_list;

    void f()
    {
    exception_list es = {
    std::make_exception_ptr(std::bad_alloc()),
    std::make_exception_ptr(std::runtime_error("run")),
    std::make_exception_ptr(std::out_of_range("out")),
    std::make_exception_ptr(int(5)),
    };
    throw es;
    }

    int main()
    {
    try {
    f();
    } catch (exception_list& es) {
    for (std::exception_ptr e: es) {
    try {
    std::rethrow_exception(e);
    } catch (std::bad_alloc& e) {
    printf("A %s
    ", e.what());
    } catch (std::runtime_error& e) {
    printf("B %s
    ", e.what());
    } catch (std::exception& e) {
    printf("C %s
    ", e.what());
    } catch (int e) {
    printf("D %d
    ", e);
    } catch (...) {
    printf("F unknown err
    ");
    }
    }
    }
    }
    ---
    % clang++ -std=c++11 t.cpp && ./a.out
    A std::bad_alloc
    B run
    C out
    D 5

  • MLNo.14101   USAGI-WRPさん  (0) 2014/09/10 15:36  [メール表示する]
    適用な制御構造とrethrowないしthrow_with_nested/rethrow_if_nestedを使うよ
    うにするとか。

    参考:
    http://www.cplusplus.com/reference/exception/rethrow_if_nested/

    On 2014年09月10日 13:36, Fumiki Fukuda wrote:
    > επιστημη@困ったときのcppll頼み です。
    >
    > 複数の例外がthrowされるシチュエーションがありまして。
    > # マルチスレッドなんかだと同時にthrowされるかも、みたいな。
    >
    > 例外をthrowする側では std::exception_ptr の集合: exception_list を
    > throwします。exception_list には begin()/end() があるので内包する
    > exception_ptrを列挙できます。そうすると、
    >
    > try {
    > try {
    > ここで exception_list がthrowされる
    > } catch ( exception_list& errors ) {
    > for ( exception_ptr eptr : errors ) {
    > std::rethrow_exception(eptr); // [*] 再throw
    > }
    > } catch ( そのほか ) {
    > ...
    > }
    > } catch ( foo_error& xxx ) {
    > // [*]でthrowされたのを捕まえる-1
    > } catch ( bar_error& yyy ) {
    > // [*]でthrowされたのを捕まえる-2
    > }
    >
    > こんなカンジかしら。
    > ...んでもこれだと exception_list のイッコ目が catch
    > されたらcatch節を抜けちゃうですよね?
    >
    > 複数の例外を捕まえるのって、どうやるんでしょ?
    >
    >
    > MLホームページ: http://www.freeml.com/cppll
    >
    > ----------------------------------------------------------------------
    > 夫婦・家族でゆったり≪温泉≫箱根・軽井沢・京都など人気のリゾ
    > ート!組数限定企画!早い者勝ち!まずはご応募下さい!
    > ■大感謝プラン(1):【平日】  ¥500〜 
    > ■大感謝プラン(2):【土・連休】¥1,500〜 
    > http://ad.freeml.com/cgi-bin/sa.cgi?id=lJMYm
    > ------------------------------------------------------[freeml byGMO]--
    >

  • MLNo.14102   επιστημηさん  (0) 2014/09/11 07:30  [メール表示する]
    επιστημηです。

    > 質問の意図をとり間違えているのかもしれませんが、for()の部分で
    > catchしたら駄目なんでしょうか。

    ...そか、それでいいか orz

    > for (std::exception_ptr e: es) {
    > try {
    > std::rethrow_exception(e);
    > } catch (std::bad_alloc& e) {
    > printf("A %s\n", e.what());
    >...

    rethrow_exceptionの一行だけを try でくるむのが
    なんともやるせないのですが、そーゆーことになりますねぇ。

    > 適用な制御構造とrethrowないしthrow_with_nested/rethrow_if_nestedを使うよ
    > うにするとか。

    ネタバレすると、並列STLの草案:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3960.pdf
    では、並列アルゴリズムに与えたファンクタ内で例外起こすと exception_ptr
    に変換し、exception_listに追加して throw される、とありまして。
    そいつを catch して列挙して...あれ? てな次第でした。

  • MLNo.14103   Egtraさん  (0) 2014/09/12 01:36  [メール表示する]
    こんばんは、Egtraです。

    > rethrow_exceptionの一行だけを try でくるむのが
    > なんともやるせないのですが、そーゆーことになりますねぇ。

    同感です、今でもstd::exception_ptrでそういうコードを書いたことがあるので。

    std::functionのtarget_typeとtargetのように、中身の型を知る・中身の型を指定して取り出す方法がstd::exception_ptrにも欲しいなあと思うことはあります。

    --
    '' Egtra (イグトランス)
    '' valp_ab@…
    ''
    '' Blog: <http://dev.activebasic.com/egtra/>
    '' Twitter: @… <https://twitter.com/egtra>

  • MLNo.14104   "MITSUNARI Shigeo"さん  (0) 2014/09/12 05:39  [メール表示する]
    光成です。

    επιστημηさん
    >タバレすると、並列STLの草案:
    >http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3960.pdf
    >では、並列アルゴリズムに与えたファンクタ内で例外起こすと exception_ptr
    >に変換し、exception_listに追加して throw される、とありまして。
    >そいつを catch して列挙して...あれ? てな次第でした。

    ちょうど、先日C++WG小委員会でparallel TSをレビューしたところだったので、
    それだろうなあと想像していました(^^;

    Egtraさん
    >> rethrow_exceptionの一行だけを try でくるむのが
    >> なんともやるせないのですが、そーゆーことになりますねぇ。
    >
    >同感です、今でもstd::exception_ptrでそういうコードを書いたことがあるので。
    >
    >std::functionのtarget_typeとtargetのように、中身の型を知る・中身の型を指定し

    >取り出す方法がstd::exception_ptrにも欲しいなあと思うことはあります。

    なるほど。あったら便利かもしれませんね。
    ちょっと他のメンバにも聞いてみます。

  • MLNo.14105   "MITSUNARI Shigeo"さん  (0) 2014/09/12 06:52  [メール表示する]
    光成です。

    >>std::functionのtarget_typeとtargetのように、中身の型を知る・中身の型
    >を指定して取り出す方法がstd::exception_ptrにも欲しいなあと思うことは
    >あります。
    >
    >なるほど。あったら便利かもしれませんね。

    とかきましたが、コード的にはあまり代わりばえしない気もしました。

    現状の

    std::exception_ptr e;

    try {
    std::rethrow_exception(e);
    } catch (std::bad_alloc& e) {
    printf("A %s
    ", e.what());
    } catch (std::runtime_error& e) {
    printf("B %s
    ", e.what());
    } catch (std::exception& e) {
    printf("C %s
    ", e.what());
    } catch (int e) {
    printf("D %d
    ", e);
    } catch (...) {
    printf("F unknown err
    ");
    }



    const std::type_info& type = e.target_type();
    if (type == typeid(std::bad_alloc)) {
    printf("A %s
    ", e.target<std::bad_alloc>()->what());
    } else if (type == typeid(runtime_error)) {
    printf("B %s
    ", e.target<std::runtime_error>()->what());
    } else if (...)

    となる感じですよね。
    比較と取り出しで、型を2回書かないといけない分、面倒な気もします。

    std::functionではそれしか方法がないのですが、std::exceptionの場合は
    まさにtry catchがあるので(型のパターンマッチといえる)現状の方がすっきり
    してるのかもしれません。

    このケース以外でtargetが便利なケースはありそうですけど。

  • MLNo.14106   Egtraさん  (0) 2014/10/13 22:15  [メール表示する]
    今更ですがEgtraです。

    std::functionのtargetのように、「指定した型で取り出せないならnullptrを返す」という仕様を想定していました。
    すると次のように書けます。
    // std::exception_ptr e;
    if (auto x = e.target<std::bad_alloc>()) {
    printf("A %s\n", x->what());
    } else if (auto x = e.target<std::runtime_error>()) {
    printf("B %s\n", x->what());
    } else if (...)

    catchと同じではないかと言われればそのとおりなのです。
    catchと比較してのよっぽどの利点がないとダメですよね。

    #例外throwに反応してデバッガが一時停止する設定の下では、
    #むやみやたらとthrowせずに済むのがありがたいです。
    #それくらいしか思いつきません。

    2014年9月12日 6:52 MITSUNARI Shigeo <herumi@…>:
    > 光成です。
    >
    >>>std::functionのtarget_typeとtargetのように、中身の型を知る・中身の型
    >>を指定して取り出す方法がstd::exception_ptrにも欲しいなあと思うことは
    >>あります。
    >>
    >>なるほど。あったら便利かもしれませんね。
    >
    > とかきましたが、コード的にはあまり代わりばえしない気もしました。
    >
    > 現状の
    >
    > std::exception_ptr e;
    >
    > try {
    > std::rethrow_exception(e);
    > } catch (std::bad_alloc& e) {
    > printf("A %s
    ", e.what());
    > } catch (std::runtime_error& e) {
    > printf("B %s
    ", e.what());
    > } catch (std::exception& e) {
    > printf("C %s
    ", e.what());
    > } catch (int e) {
    > printf("D %d
    ", e);
    > } catch (...) {
    > printf("F unknown err
    ");
    > }
    >
    > が
    >
    > const std::type_info& type = e.target_type();
    > if (type == typeid(std::bad_alloc)) {
    > printf("A %s
    ", e.target<std::bad_alloc>()->what());
    > } else if (type == typeid(runtime_error)) {
    > printf("B %s
    ", e.target<std::runtime_error>()->what());
    > } else if (...)
    >
    > となる感じですよね。
    > 比較と取り出しで、型を2回書かないといけない分、面倒な気もします。
    >
    > std::functionではそれしか方法がないのですが、std::exceptionの場合は
    > まさにtry catchがあるので(型のパターンマッチといえる)現状の方がすっきり
    > してるのかもしれません。
    >
    > このケース以外でtargetが便利なケースはありそうですけど。
    >
    >
    >
    > MLホームページ: http://www.freeml.com/cppll
    >
    > ----------------------------------------------------------------------
    > 夫婦・家族でゆったり≪温泉≫箱根・軽井沢・京都など人気のリゾ
    > ート!組数限定企画!早い者勝ち!まずはご応募下さい!
    > ■大感謝プラン(1):【平日】  ¥500~
    > ■大感謝プラン(2):【土・連休】¥1,500~
    > http://ad.freeml.com/cgi-bin/sa.cgi?id=lKtTD
    > ------------------------------------------------------[freeml byGMO]--
    >



    --
    '' Egtra (イグトランス)
    '' valp_ab@…
    ''
    '' Blog: <http://dev.activebasic.com/egtra/>
    '' Twitter: @… <https://twitter.com/egtra>


メールへの返信はMLのメンバーしかできません。

更新順メールリスト