我找到了关于c 中构造函数的异常的矛盾答案。此链接中的答案之一说,如果在构造函数内部抛出异常,则假定构造不完整,因此未调用破坏者。但是,此链接使用在构造函数中创建并在灾难中清理的静音示例讨论了RAII概念。它说,如果在构造函数中创建了一个静音词,然后构造函数调用一个抛出示意的函数,并且没有例外的处理程序,则仍将调用驱动器,然后将调用互斥符,并清理静音。什么我是否缺少?
未执行所构造的对象的驱动器,但构造的所有成员都会破坏;例如:
struct A {
A(int x) { ... }
~A() { ... }
};
struct B {
A a1, a2, a3;
B() : a1(1), a2(2), a3(3) { ... }
~B() { ... }
};
如果在构建B
实例时,a1
的构建良好,则a2
的构建很好,但是a3
的构建抛出了例外,那么a2
将被销毁(调用~A
(,那么a1
将被销毁但是~B
不会因为构造函数没有完成(身体都没有启动(而被召唤。
即使在B()
的...
主体内抛出了例外,所有A
subobjects都会通过调用~A
销毁,但仍然不会调用~B
。
仅当B
的构造函数是完成的您获得的是真正的B
实例,然后当被销毁时,~B
将被调用以执行破坏代码。
让我们看一下这个代码:
#include <iostream>
#include <stdexcept>
class A {
public:
A() {
std::cout << "A's constructorn";
}
~A() {
std::cout << "A's destructorn";
}
};
class B {
public:
B() {
std::cout << "B's constructor - beginn";
throw std::runtime_error("Error");
std::cout << "B's constructor - endn";
}
~B() {
std::cout << "B's destructorn";
}
private:
A a;
};
int main() {
try {
B b;
} catch(const std::runtime_error& exc) {
std::cerr << exc.what() << 'n';
}
}
这是程序的输出:
A's constructor
B's constructor - begin
A's destructor
Error
通常,首先构造对象时,将调用其文件的构造函数,然后执行对象的构造函数。对于每个成功执行的构造函数,都必须有一个灾难。攻击子以相反的顺序称为。如果构造函数失败,则没有命令仪,但是如果在构造物体期间,其某些字段被构建,则将被摧毁。
回到示例,在main
函数中,我创建了类B
的对象。该对象包含A
类的成员。创建b
对象时,首先构建了它的字段(在这种情况下,它是称为a
的成员( - 这是输出的第一行。然后,b
对象的构造函数开始执行(输出的第二行(。B
的构造器会引发异常。由于b
的字段(即a
的构造函数(的创建器已经成功执行,因此必须称为a
的Destructor-输出线。现在,b
的构造函数尚未成功完成其执行,因此destructor不会被要求使用b
。输出的最后一行是main
函数中异常处理代码的效果。
在此示例中,您可以看到,当构造函数成功时,一段时间以后将调用相应的破坏者。但是,如果构造函数失败,则不会调用对象的破坏者。
成功执行的构造函数和破坏者总是配对。这是一个非常一般的规则,也适用于基类(如果有的话(,在阵列中分配的对象,分配在堆栈等的对象等。-即使是非常奇怪且复杂的情况。