C++ C++;是否调用引发异常的类?

C++ C++;是否调用引发异常的类?,c++,resources,destructor,acquisition,C++,Resources,Destructor,Acquisition,假设我有一个这样的类: #include <iostream> using namespace std; class Boda { private: char *ptr; public: Boda() { ptr = new char [20]; } ~Boda() { cout << "calling ~Boda\n";

假设我有一个这样的类:

#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 b
对象没有被破坏

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

还有,这就是所谓的
RAII


谢谢,Boda Cydo。

< P>如果异常没有被捕获到任何地方,那么C++运行时可以自由地终止程序而不进行任何堆栈解散或调用任何析构函数。 但是,如果您在对
bad()
的调用周围添加try-catch块,您将看到正在调用的
Boda
对象的析构函数:

int main() {
    try {
      bad();
    } catch(...) {  // Catch any exception, forcing stack unwinding always
      return -1;
    }
}
RAII意味着动态(堆)分配的内存始终由自动(堆栈)分配的对象拥有,该对象在销毁时将其解除分配。这依赖于在自动分配的对象超出范围时调用析构函数的保证,无论是由于正常返回还是由于异常


对于RAII来说,这种情况下的行为通常不是问题,因为通常希望析构函数运行的主要原因是释放内存,并且当程序终止时,所有内存都会返回给操作系统。但是,如果您的析构函数执行更复杂的操作,例如删除磁盘上的锁文件或其他操作,程序崩溃时调用析构函数与否会产生差异,则您可能希望将
main
包装在一个try-catch块中,该块捕获所有内容(仅在出现异常时退出)只是为了确保堆栈在终止之前总是展开。

尝试刷新流-您将看到析构函数确实被调用:

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

如果构造函数中发生异常,则不会运行析构函数

如有必要(若异常在某处被处理),若异常在另一个方法(如示例中)中引发,它将运行。但当程序终止时,这里不需要调用析构函数,并且行为取决于编译器

RAII
的思想是构造函数分配资源,析构函数释放资源。如果构造函数中发生异常,没有简单的方法可以知道哪些资源在哪里分配,哪些没有(这取决于异常发生在构造函数中的确切位置)。您还应该记住,如果构造函数失败,那么向调用者报告它以引发异常并释放已分配内存的唯一方法(堆栈展开或堆分配内存)就好像从未分配过一样

解决方案是显而易见的:如果构造函数中可能发生任何异常,您必须捕获它并在必要时释放已分配的资源。它实际上可能是一些使用析构函数的重复代码,但这不是一个大问题

在析构函数中,您不应该引发异常,因为它可能导致堆栈展开的大麻烦


在任何其他方法中,可以随意使用异常,但不要忘记在某个地方处理它们。未经处理的例外可能比没有例外更糟糕。我知道有些程序不处理一些小错误的异常。。。如果嵌入式
\n
指向终端,则嵌入式
\n
将刷新流。@Tyler:您能指出嵌入式
\n
将刷新终端的某个位置吗?我发现情况并非如此,但我不确定我是否只在文件中注意到。嗯,谁告诉你的?请阅读:哦,对不起,进一步阅读后,我认为flush on-
\n
是一个gcc ism,由C99带来。谢谢,这解释了很多。但如果我有更复杂的情况呢?比如在几个地方分配内存?然后,如果调用析构函数,我可能会遇到这样一种情况:对尚未实际分配的指针调用delete(或free)(因为有几个位置)。这会导致出现一些标志,如
bool allocated\u in_place\u 1,allocated\u in_place\u 2,…
。在析构函数中,我必须像
if(在位置1中分配位置)删除位置1;如果(在位置2中分配位置)删除[]位置位置2数组\u ptr你对此有什么建议吗?我不能直接去
删除位置\u 1\u ptr;delete[]将_2_array _ptr
放在dtor中,对吗?是的,如果有一个对象要管理一些复杂的动态内存组合,它确实需要跟踪它实际分配了哪些内存和没有分配哪些内存,以便它可以删除析构函数中的正确内容。但若您只需确保并没有分配内存的指针总是设置为
NULL
,那个么这很容易做到。而且你自己写这样一个类也不常见。通常你会想使用STL容器或智能指针。哦,是的。我忘了如果它们是
NULL
就没关系了。你可以只写
delete place\u 1\u ptr;如果确定两个指针都已分配或为空,请删除[]place_2_array_ptr
。删除空指针是合法的,这样做时不会发生任何事情。
cout << "calling ~Boda" << endl;