C言語関係掲示板

過去ログ

No.1202 関数スコープでの例外処理

[戻る] [ホームページ]
No.15709

関数スコープでの例外処理
投稿者---isshi(2004/07/20 23:08:11)


No.15707の続きです。

シャノンさん、レスありがとうございます。
まず、ExceptionTest クラスのコンストラクタは、誤記でしょうか?
(はじめてみる書き方なので。。)
もし誤記でなければ、そもそもVC6ではコンパイルできませんでした。

下記コードが正解だった場合、
public:
  ExceptionTest() : thrower()
  {
    try  // *1
    {
    }
    catch( ExceptionThrower * )  // *2
    {
      std::cout << "ExceptionThrower 例外を ExceptionTest コンストラクタで補足しました。" << std::endl;
      throw;
    }
  }

コンストラクタ本体に入る前の初期化で例外が発生するため *1 の try には入っていないので、*2 で catch されなくて当然だと思うのですが。

また、どのへんが「関数スコープでの例外処理」なのか分かりませんでした。



No.15712

Re:関数スコープでの例外処理
投稿者---Ban(2004/07/21 03:10:31)


発端のレスを書いた張本人です。
正式な名称は確認してませんが下記のような記法です。

#include <iostream>

void
foobar()
try  // 関数に対してこういうスコープを指定
{
    throw 1;    // この例外を
}
catch(...)
{
    std::cout << "hit" << std::endl;    // ここで拾える
}

int
main()
{
    foobar();
    return 0;
}


※VC7.1 では通りますが、VC6ではコンパイルエラーです。

何に使えるのかといわれると微妙ですが、
本来的には、コンストラクタの初期化記述中での例外処理を
内部で補足するために追加されたとかされないとか...
というものらしいです。


No.15714

Re:関数スコープでの例外処理
投稿者---Ban(2004/07/21 04:09:39)


>正式な名称は確認してませんが下記のような記法です。

言語規格(IS)を確認しましたが、function-try-block が正式名でした。

日本語でなんと表現するのが正しいのかまでは分かりませんが、
この記法だと関数の() 直後から {} の終端までを範囲に指定できるので、
私なりに関数スコープという表現を使っていました。
# 私が命名(?)した由来は前のレスのコードを見ていただくと
# 分かりやすいかもしれません。

勿論、シャノンさんの記述はこの標準に準拠したもので誤記ではありません。

で、効果としては、前でも少し触れたようにコンストラクタでより効果を
発揮するもので、isshi さんの修正されたVC6でも通る例とは異なり、
シャノンさんの例では初期化(thrower内)で例外が発生しても、
そこが try の内側であるために、*2 に相当する catch で捕捉する
ことができるというものです。

VC6 でも、コンストラクタの関数本体で try ブロックを作成して
代入すれば大抵問題にはならないのですが、初期化が必須な、
例えばconst なメンバなどで例外が発生し得るような場合には、
VC6 では呼出側で catch してもらうしかないところを、
標準準拠の実装系だとこの構文で内部吸収することもできると
いうことです。

シャノンさん、毎度のフォローありがとうございました。


No.15718

Re:関数スコープでの例外処理
投稿者---シャノン(2004/07/21 07:48:05)


>言語規格(IS)を確認しましたが、function-try-block が正式名でした。
>
>日本語でなんと表現するのが正しいのかまでは分かりませんが、

日本語では「関数監視ブロック」と言うそうです。
JIS X 3014:2003 p235-237 [15.例外処理] より


No.15720

Re:関数スコープでの例外処理
投稿者---isshi(2004/07/21 08:00:15)


Banさん、シャノンさん、ありがとうございます。
なるほど、よく分かりました。
まだまだ勉強が足りないと痛感しました。
規格書、買おうかな。。



No.15723

Re:関数スコープでの例外処理
投稿者---Ban(2004/07/21 08:50:23)


>日本語では「関数監視ブロック」と言うそうです。
>JIS X 3014:2003 p235-237 [15.例外処理] より

JIS 版の方はさすがに持っていないので勉強になります。

とはいえ、勝手に呼んでただけの適当な意訳よりはマシだとしても、
なんかあまり通じなさそうな気が....。
以後はちゃんと「ファンクション・トライ・ブロック」と
覚えようと思います。


No.15719

Re:関数スコープでの例外処理
投稿者---YuO(2004/07/21 07:58:30)


>VC6 でも、コンストラクタの関数本体で try ブロックを作成して
>代入すれば大抵問題にはならないのですが、初期化が必須な、
>例えばconst なメンバなどで例外が発生し得るような場合には、
>VC6 では呼出側で catch してもらうしかないところを、
>標準準拠の実装系だとこの構文で内部吸収することもできると
>いうことです。

根本的に,初期化処理中の例外は吸収することはできません。

IS 15.3 Handling an exceptionのParagraph 15
>If a return statement appears in a handler of the function-try-block of a constructor, the program is ill-formed.
とParagraph 16
>The exception being handled is rethrown if control reached the end of a handler of the function-try-block of a constructor or destructor.
により,コンストラクタの関数tryブロックの例外ハンドラからの脱出は例外送出によるしかなくなります。

これは当然といえば当然の話で,コンストラクタの関数tryブロックの例外ハンドラからreturnで脱出できると,
初期化処理がなされていない,中途半端なオブジェクトへのアクセスができるようになってしまいます。



No.15721

Re:関数スコープでの例外処理
投稿者---Ban(2004/07/21 08:40:15)


>根本的に,初期化処理中の例外は吸収することはできません。
  --- snip ---
>これは当然といえば当然の話で,コンストラクタの関数tryブロックの例外ハンドラからreturnで脱出できると,
>初期化処理がなされていない,中途半端なオブジェクトへのアクセスができるようになってしまいます。

そういえばそうでした.....黙殺されたら大迷惑だorz。
コンストラクタの初期化の場合には
「自分の後始末をする最後のチャンスが得られる」
くらいの認識の方が適切ですね。
ご指摘ありがとうございます。



No.15722

Re:関数スコープでの例外処理
投稿者---isshi(2004/07/21 08:42:41)


>根本的に,初期化処理中の例外は吸収することはできません。

となると、function-try-block の存在意義がどこにあるのかよくわからないですね。
思いつく利用法としては、初期化時の例外をコンストラクタで catch して、
独自の例外を投げることができる、くらいです。
とりあえず、どういうものか分かったので、もう少し調べてみたいと思います。
(VC6しかないので使いたくても使えませんが。。)