関数 try ブロック・ハンドラー (C++ のみ)

関数またはコンストラクターのパラメーターのスコープおよび存続時間が、 関数 try ブロックのハンドラーにまで適用されます。 次の例は、このことを示しています。
void f(int &x) try {
   throw 10;
}
catch (const int &i)
{
   x = i;
}

int main() {
   int v = 0;
   f(v);
}
f() が呼び出された後は、v の値は、10 になります。

main() の関数 try ブロックは、静的ストレージ期間を持つオブジェクトのデストラクターで、 またはネーム・スペース・スコープ・オブジェクトのコンストラクターで、 スローされる例外をキャッチしません。

次の例は、静的オブジェクトのデストラクターから例外をスローします。この例の意図は、~B() の例外は main() の関数 try ブロックによってキャッチされるが、~A() の例外は、~A()main() の完了後に実行されるため、キャッチされないことを示すことです。

#include <iostream>
using namespace std;

class E {
public:
  const char* error;
  E(const char* arg) : error(arg) { }
};

class A {
  public: ~A() { throw E("Exception in ~A()"); }
};

class B {
  public: ~B() { throw E("Exception in ~B()"); }
};

int main() try {
  cout << "In main" << endl;
  static A cow;
  B bull;
}
catch (E& e) {
  cout << e.error << endl;
}
上記の例の出力は、以下のとおりです。
In main
Exception in ~B()
ランタイムは、オブジェクト cow が、 プログラムの終わりに破棄される時にスローされる例外をキャッチできません。
次の例は、ネーム・スペース・スコープ・オブジェクトのコンストラクターから例外をスローします。
#include <iostream>
using namespace std;

class E {
public:
  const char* error;
  E(const char* arg) : error(arg) { }
};

namespace N {
  class C {
  public:
    C() {
      cout << "In C()" << endl;
      throw E("Exception in C()");
    }
  };

  C calf;
};

int main() try {
  cout << "In main" << endl;
}
catch (E& e) {
  cout << e.error << endl;
}
上記の例の出力は、以下のとおりです。
In C()
コンパイラーは、オブジェクト calf の作成時にスローされる例外をキャッチできません。

関数 try ブロックのハンドラーでは、コンストラクター本体、 またはデストラクター本体にジャンプすることはできません。

リターン・ステートメントは、コンストラクターの関数 try ブロック・ハンドラー内に置くことはできません。

オブジェクトのコンストラクター、またはデストラクターの関数 try ブロック・ハンドラーに入ると、 そのオブジェクトの完全な構成の基底クラスおよびメンバーは、破棄されます。 次の例は、このことを示しています。
#include <iostream>
using namespace std;

class E {
   public:
      const char* error;
      E(const char* arg) : error(arg) { };
};

class B {
   public:
      B() { };
      ~B() { cout << "~B() called" << endl; };
};

class D : public B {
   public:
      D();
      ~D() { cout << "~D() called" << endl; };
};

D::D() try : B() {
   throw E("Exception in D()");
}
catch(E& e) {
   cout << "Handler of function try block of D(): " << e.error << endl;
};

int main() {
   try {
      D val;
   }
   catch(...) { }
}
上記の例の出力は、以下のとおりです。
~B() called
Handler of function try block of D(): Exception in D()
D() の関数 try ブロックのハンドラーに入ると、 ランタイムは、まず最初に D の基底クラスのデストラクター、 つまり B を呼び出します。 val が完全に構成されていないので、D のデストラクターは呼び出されません。
ランタイムは、コンストラクターまたはデストラクターの関数 try ブロックのハンドラーの終了時に、 例外を再スローします。 その他のすべての関数は、関数 try ブロックのハンドラーの終了に到達した時点でリターンします。 次の例は、このことを示しています。
#include <iostream>
using namespace std;

class E {
   public:
      const char* error;
      E(const char* arg) : error(arg) { };
};

class A {
   public:
      A() try { throw E("Exception in A()"); }
      catch(E& e) { cout << "Handler in A(): " << e.error << endl; }
};

int f() try {
   throw E("Exception in f()");
   return 0;
}
catch(E& e) {
   cout << "Handler in f(): " << e.error << endl;
   return 1;
}

int main() {
   int i = 0;
   try { A cow; }
   catch(E& e) {
      cout << "Handler in main(): " << e.error << endl;
   }

   try { i = f(); }
   catch(E& e) {
      cout << "Another handler in main(): " << e.error << endl;
   }

   cout << "Returned value of f(): " << i << endl;
}
上記の例の出力は、以下のとおりです。
Handler in A(): Exception in A()
Handler in main(): Exception in A()
Handler in f(): Exception in f()
Returned value of f(): 1
C++0x
委任プロセスが存在し、例外がターゲット・コンストラクターの本体で発生した場合、その例外は委任コンストラクターの try ブロックにある適切なハンドラーによってキャッチできます。次の例は、このことを示しています。
#include <cstdio>
using std::printf;

int global_argc;

struct A{
   int _x;
   A();
   A(int);
};

A::A(int x):_x((printf("In A::A(int) initializer for A::_x.¥n"),x)){
   printf("In A::A(int) constructor body.¥n");

   if(global_argc % 2 !=0){
      printf("Will throw.¥n");
      throw 0;
   }
   printf("Will not throw.¥n");
}

A::A() try:A((printf("In A::A() initializer for delegating to A::A(int).¥n"),42)){
   printf("In A::A() function-try-block body.¥n");
}
catch(...){
   printf("In catch(...) handler for A::A() function-try-block.¥n");
}

int main(int argc, char **argv){
   printf("In main().¥n");
   global_argc = argc;
   try{
      A a;
      printf("Back in main().¥n");
   }
   catch(...){
      printf("In catch(...) handler for try-block in main().¥n");
   }
   return 0;
}
この例は、生成されるプログラムの呼び出し時に受け渡される引数の数に応じて、異なる出力を生成できます。 引数が偶数個の場合、例外がスローされます。出力は次のとおりです。
In main().
In A::A() initializer for delegating to A:A(int).
In A::A(int) initializer for A::_x.
In A::A(int) constructor body.
Will throw.
In catch(...) handler for A::A() function-try-block.
In catch(...) handler for try-block in main().
引数が奇数個の場合、例外はスローされません。出力は次のとおりです。
In main().
In A::A() initializer for delegating to A::A(int).
In A::A(int) initializer for A::_x.
In A::A(int) constructor body.
Will not throw.
In A::A() function-try-block body.
Back in main().

詳細については、委任コンストラクター (C++0x)を参照してください。

C++0x