假设我有这样的课:

#include <iostream>

using namespace std;

class Boda {
    private:
        char *ptr;

    public:
        Boda() {
            ptr = new char [20];
        }
        ~Boda() {
            cout << "calling ~Boda\n";

            delete [] ptr;
        }

        void ouch() {
            throw 99;
        }
};

void bad() {
    Boda b;
    b.ouch();
}

int main() {
    bad();
}

看来那个驱动器 ~Boda 从不打电话,因此 ptr 资源永远不会被释放。

这是程序的输出:

terminate called after throwing an instance of 'int'
Aborted

所以看来我问题的答案是 No.

但是我以为当例外时,堆栈变得解开了吗?为什么没有 Boda b 在我的示例中,对象被破坏了吗?

请帮助我了解这个资源问题。我想在将来编写更好的程序。

另外,这是所谓的 RAII?

谢谢,Boda Cydo。

有帮助吗?

解决方案

如果没有在任何地方捕获异常,则C ++运行时可以免费直接终止程序,而无需进行任何堆栈放松或调用任何破坏者。

但是,如果您在调用周围添加一个trycatch块 bad(), ,您会看到 Boda 被调用的对象:

int main() {
    try {
      bad();
    } catch(...) {  // Catch any exception, forcing stack unwinding always
      return -1;
    }
}

raii 意味着分配的(堆)分配的内存始终由自动(堆栈)分配的对象拥有,当对象破坏时对其进行处理。这依赖于这样的保证,即当自动分配的对象脱离范围时,无论是由于正常返回还是由于异常,将调用损坏器。

这种角案案例的行为通常不是RAII的问题,因为通常您希望破坏者运行的主要原因是自由记忆,并且当您的程序终止时,所有内存都会回到OS中。但是,如果您的破坏者做一些更复杂的事情,例如删除磁盘上的锁定文件或其他内容,无论是在崩溃时称为destuructors是否称为destructors,您可能都想包装您的 main 在一个捕获所有内容的试用块中(无论如何仅在异常上退出),以确保堆栈始终在终止之前放松。

其他提示

如果在构造函数中发生异常,则将无法运行驱动器。

如果需要(如果在某个地方处理异常),如果在您的示例中提出异常,它将运行(如果在某个地方处理异常)。但是,随着程序的终止,在这里没有必要调用灾权程序,并且编译器的行为取决于...

这个想法 RAII 这是构造函数分配的,并释放了它们。如果在构造函数中发生异常,则没有简单的方法可以知道分配和不分配的wich ressources(这取决于发生异常的构造函数的确切位置)。您还应该记住,如果构造函数失败,则唯一可以呼叫它来提出例外的方法 分配的内存被释放(堆叠放松或堆放分配的内存),就好像从未分配。

该解决方案很明显:如果在构造函数中可能发生任何例外,则必须捕获它并在必要时免费分配的Ressources。实际上,这可能是一些与Destructor相关的重复代码,但这不是一个大问题。

在破坏者中,您不应提出例外,因为它可能会带来堆栈放松的大麻烦。

在任何其他方法中,请随意使用异常,但不要忘记在某个地方处理它们。未经治疗的概论可能比没有例外更糟糕。我知道一些程序没有处理一些小错误的例外……并且出于仅发出警告的错误而崩溃。

尝试冲洗流 - 您会看到毁灭者确实被称为:

cout << "calling ~Boda" << endl;

是I/O的缓冲将打印输出延迟到实际输出之前的程序终止切割。

编辑:

以上是 处理例外. 。和 未经治疗的例外 该标准未指定堆栈是否已解开。也可以看看 这个问题.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top