Q015-关于构造函数抛出异常

Q015

Copy
#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();
}
}

Answer

click to see answer
acabBA

Explain

在 try 中调用 foo() 函数，该函数中定义了一个局部静态变量 b。在构造 b 对象时，会先构造 B 类的成员变量 a，a 调用 A 对象的默认构造函数，输出 a，然后对 x 进行判断，因为是后置 ++（先使用后增加），所以判断时 x == 0，执行抛出异常的操作 throw exception()，catch (std::exception &) 捕获到该异常后输出 c，并调用 foo() 函数，进入 foo() 函数，因为在 try 中执行该函数时，局部静态变量 b 并未完成初始化，所以将再次对 b 进行初始化，先构造 B 类成员变量 a，调用 A 对象默认构造函数，输出 a，然后对 x 进行判断，当前 x != 0，所以不执行抛出异常的操作，成员变量 a 构造完成，开始调用 B 的默认构造函数，输出 b，在程序终止后，局部静态变量 b 开始析构，先调用 b 的析构函数，输出 B，再调用成员变量 a 析构函数，输出 A。

构造函数中抛出异常，可能会使对象部分构造，随之就有可能导致资源泄漏或不一致的对象状态，所以应避免在构造函数中抛出异常