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

次の例は、静的オブジェクトのデストラクターから例外をスローします。

#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

関連参照

IBM Copyright 2003