关于C 构造函数中例外的混乱

Confusion regarding exceptions in C++ constructors

本文关键字:混乱 构造函数 关于      更新时间:2023-10-16

我找到了关于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函数中异常处理代码的效果。

在此示例中,您可以看到,当构造函数成功时,一段时间以后将调用相应的破坏者。但是,如果构造函数失败,则不会调用对象的破坏者。

成功执行的构造函数和破坏者总是配对。这是一个非常一般的规则,也适用于基类(如果有的话(,在阵列中分配的对象,分配在堆栈等的对象等。-即使是非常奇怪且复杂的情况。