是否会调用抛出异常的C++类的析构函数?

bod*_*ydo 6 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";

            delete [] ptr;
        }

        void ouch() {
            throw 99;
        }
};

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

int main() {
    bad();
}
Run Code Online (Sandbox Code Playgroud)

似乎析构函数~Boda永远不会被调用,因此ptr资源永远不会被释放.

这是程序的输出:

terminate called after throwing an instance of 'int'
Aborted
Run Code Online (Sandbox Code Playgroud)

所以似乎我的问题的答案是No.

但是当我抛出一个异常时,我认为堆栈被解开了?为什么没有Boda b对象在我的例子中被破坏?

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

这也就是所谓的RAII

谢谢,Boda Cydo.

Tyl*_*nry 8

如果异常没有被捕获到任何地方,那么C++运行时可以直接终止程序,而无需进行任何堆栈展开或调用任何析构函数.

但是,如果在调用周围添加try-catch块bad(),您将看到Boda被调用对象的析构函数:

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

RAII意味着动态(堆)分配的内存总是由自动(堆栈)分配的对象拥有,该对象在对象析构时释放它.这依赖于保证在自动分配的对象超出范围时将调用析构函数,无论是由于正常返回还是由于异常.

这种角落情况通常不是RAII的问题,因为通常你想要析构函数运行的主要原因是释放内存,并且当程序终止时,所有内存都会返回给操作系统.但是,如果你的析构函数做了一些更复杂的事情,比如可能删除磁盘上的锁文件或其他东西,那么在崩溃时程序是否会调用析构函数会有所不同,你可能想要将它包装main在一个捕获的try-catch块中所有事情(仅在异常时退出)只是为了确保堆栈在终止之前总是展开.