何时初始化静态局部变量? 如果在构造函数中抛出异常,是否构造了对象?析构函数会被调用吗?
考虑暂停代码:
#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
第一次调用foo()时,尝试初始化b。调用它的构造函数,它首先构造所有成员变量。这意味着调用A :: A(),打印a。 A :: A()然后抛出异常,构造函数被中止,b或B :: a实际上都不被认为是构造的。
为什么b第一次没有初始化?
答案 0 :(得分:3)
每次控制传递变量定义时,都会尝试初始化具有静态存储持续时间的块作用域变量,直到成功为止。
来自[stmt.dcl] / 4:
动态初始化具有静态存储持续时间(3.7.1)或线程存储的块范围变量 持续时间(3.7.2)是在控制第一次通过其声明时执行的;考虑这样的变量 初始化完成后初始化。 如果初始化通过抛出异常退出,则 初始化未完成,因此下次控件进入声明时将再次尝试。
如果任何成员的构造抛出异常,那么B
类型的对象的构造当然不能完成。