引发异常的C ++类的驱动器会被调用吗?
-
01-10-2019 - |
题
假设我有这样的课:
#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的缓冲将打印输出延迟到实际输出之前的程序终止切割。
编辑:
以上是 处理例外. 。和 未经治疗的例外 该标准未指定堆栈是否已解开。也可以看看 这个问题.