Q015#
#include <iostream>
#include <exception>
int x = 0;
class A {
public:
A() {
std::cout << 'a';
if (x++ == 0) {
throw std::exception();
}
}
~A() {
std::cout << 'A';
}
};
class B {
public:
B() {
std::cout << 'b';
}
~B() {
std::cout << 'B';
}
A a;
};
void foo() {
static B b;
}
int main() {
try {
foo();
} catch (std::exception &) {
std::cout << 'c';
foo();
}
}
答え#
答えを見るにはクリックしてください
acabBA説明#
try
ブロック内で foo()
関数を呼び出します。この関数では、ローカルな静的変数 b
を定義しています。b
オブジェクトの構築時には、まず B
クラスのメンバ変数 a
を構築します。a
は A
オブジェクトのデフォルトコンストラクタを呼び出し、a を出力します。その後、x
を判定し、後置 ++
(使用後に増加)なので、判定時に x == 0
となり、例外をスローします throw std::exception()
。catch (std::exception &)
でこの例外をキャッチし、c を出力し、foo()
関数を呼び出します。foo()
関数に入ると、try
ブロック内でこの関数を実行する際に、ローカルな静的変数 b
が初期化されていないため、再度初期化されます。まず、B
クラスのメンバ変数 a
を構築し、A
オブジェクトのデフォルトコンストラクタを呼び出し、a を出力します。その後、x
を判定し、現在の x != 0
なので、例外をスローする操作は実行されません。メンバ変数 a
の構築が完了したら、B
のデフォルトコンストラクタを呼び出し、b を出力します。プログラムが終了すると、ローカルな静的変数 b
の破棄が始まり、まず b
のデストラクタが呼び出され、B を出力します。次に、メンバ変数 a
のデストラクタが呼び出され、A を出力します。
コンストラクタで例外をスローすると、オブジェクトの一部の構築が行われない可能性があり、それによってリソースリークや一貫性のないオブジェクトの状態が発生する可能性があるため、コンストラクタで例外をスローすることは避けるべきです。