43

try-catch私は最近、関数のためにこの構文に出くわしました。

struct A
{
  int a;

  A (int i) : a(i)  // normal syntax
  {
    try {}
    catch(...) {}
  }

  A ()   // something different
  try : a(0) {}
  catch(...) {}

  void foo ()  // normal function
  try {}
  catch(...) {}
};

どちらの構文も有効です。コーディングスタイル以外に、これらの構文に技術的な違いはありますか?構文の1つは、他の構文よりも優れていますか?

4

4 に答える 4

45

最初の構文:
tryブロックのスコープは、Member Initializationリストが完了した後に開始されるため、Member Initialization中にスローされた例外は、このtry-catchブロックによってキャッチされません。

2番目の構文:
メンバー初期化リスト中に例外がスローされた場合に、例外をキャッチできるようにします。

3番目の構文:
関数本体内のtryブロックの開始中括弧の間からスローされた例外が適切にキャッチされるようにします。これは、引数の受け渡し中に発生した例外(発生する可能性がある場合)がこのtryでキャッチされないことを意味します。 -キャッチブロック。

そうです、それらは提供する機能がはっきりと異なります。


編集:
コンストラクタとデストラクタで2番目の構文(function-try-block)を使用する際に考慮すべきいくつかのガイドライン:

C ++標準に従って、

catchブロックがスローせず(元の例外を再スローするか、何か新しいものをスローする)、制御がコンストラクタまたはデストラクタのcatchブロックの終わりに達すると、元の例外が自動的に再スローされます。

簡単に言う
と、コンストラクタまたはデストラクタのfunction-try-blockのハンドラコードは、例外を発行して終了する必要があります

ガイドライン1:
コンストラクターのfunction-try-blockハンドラーには、例外を変換するという1つの目的しかありません。(そして、ロギングやその他の副作用を行うためかもしれません。)これらは他の目的には役立ちません。

デストラクタから例外をスローすることは悪い考えです。理由を知るためにここを見てください。
ガイドライン2:
デストラクタfunction-try-blocksは実際にはまったく使用されていません。彼らが検出するものは決してないはずです。悪意のあるコードのために検出するものがあったとしても、ハンドラーは例外を抑制できないため、それについて何もするのにあまり役立ちません。

ガイドライン3:
コンストラクタまたはデストラクタのfunction-try-blockハンドラではなく、コンストラクタまたはデストラクタ本体内のローカルのtry-blockハンドラでアンマネージリソースの取得を常にクリーンアップします。


標準的なファンの場合:

C ++標準、条項15.3、段落15:

コンストラクターのfunction-try-blockのハンドラーにreturnステートメントが表示される場合、プログラムの形式は正しくありません。

C ++標準、条項15.3、段落16:

コンストラクタまたはデストラクタのfunction-try-blockのハンドラの最後に制御が到達すると、処理中の例外が再スローされます。それ以外の場合、関数は、制御がfunction-try-block(6.6.3)のハンドラーの最後に到達したときに戻ります。function-try-blockの終わりからフローすることは、値のないリターンと同等です。これにより、値を返す関数(6.6.3)で未定義の動作が発生します。


参考資料:詳細と説明については、こちらのリソースを参照して
ください。

于 2011-07-20T04:19:04.683 に答える
9

Function-try-blockは、初期化リストで例外をキャッチする他の方法がないため、主にコンストラクターで役立ちます。デストラクタでは、例外が自動的に再スローされるため、catchブロックに戻るように注意する必要があります。(そして、優れた設計では、デストラクタはスローしてはなりません。)通常の機能では、この機能は役に立ちません。編集:古いがまだ良い記事:http ://drdobbs.com/184401316

于 2011-07-20T04:54:29.563 に答える
3

仕様を引用することもできます...または少なくともドラフト

セクション15(4):

function-try-blockは、handler-seqctor-initializer(存在する場合)およびcompound-statementに関連付けます。複合ステートメントの実行中にスローされた例外、またはコンストラクターとデストラクタの場合は、クラスのサブオブジェクトの初期化または破棄中に、スローされた例外と同じ方法で、 function-try-blockのハンドラーに制御を転送します。 try-blockの実行中に、制御が他のハンドラーに転送されます。

(ここで、handler-seqはtheの後のものでありcatch、thecompound-statementは関数本体です。)

したがって、コンストラクタまたはデストラクタの「関数tryブロック」は、ctor-initializersおよびサブオブジェクトの構築または破棄によってスローされた例外をキャッチします。

コンストラクタまたはデストラクタ以外の関数では、関数本体を単純にラップするのと同じです。(まあ、私が仕様を読むことから識別できる限り。)

興味深い機能であり、私にとっては新しいものです。それを持ってきてくれてありがとう。

于 2011-07-20T04:28:46.970 に答える
2

「何か違う」例では、初期化子リストの処理をtryブロックのスコープ内に置きます。

于 2011-07-20T04:18:11.703 に答える