如果一个函数提前返回或抛出异常,对象的析构函数会被调用吗?

3
在下面的代码中,我使用一个“包装对象”来暂时将一些来自数据库的东西存储在内存中。我的问题很简单:
我可以确定析构函数被调用吗?我特别担心以下情况: a) testCondition 为 true,并且函数从构造 tempObj 的作用域的内部作用域返回 b) 在执行此函数时发生某些运行时错误(在较高级别上捕获)
(作为附带问题:这是临时存储数据的好方法吗?在我的应用程序中,someFunc() 是当前数据库的保存/导出函数。)
class TempStore
{
public:
    TempStore() {/* delete some stuff from a db and store this in memory*/}
    ~TempStore() {/* write this stuff back into the db*/}
};

void someFunc(bool testCondition)
{
    TempStore tempObj = TempStore();
    // some code
    if (testCondition)
        return; //early return
    // some more code
}

你是否尝试过添加日志(例如printf或写入文件)和调试?在你展示的代码中,析构函数将被调用。 - John Odom
1
什么是运行时错误?C++异常?那么它就会工作。如果你的程序真的失败了,出现了段错误等问题,那么它就不会工作。 - mkaes
1
是的,在“someFunc()”函数返回时,假设程序执行正常(例如没有崩溃或分段错误),将调用TempStore的析构函数。这被称为“资源获取即初始化”(RAII)习语,并且是现代C ++的基石。 - In silico
是的,我有,并且它似乎运行良好。但是,由于我刚开始合作一个大型项目,我还不知道所有依赖项和可能的运行时错误和问题,因此我希望获得一些“语法保证”,以确保我的对象在任何情况下都会被销毁。 - mr_T
3个回答

6
自动对象的析构函数会在程序离开该对象的作用域时被调用。这包括从函数返回(无论是提前还是正常返回),以及通过异常离开,只要异常得到处理。如果出现异常,在处理异常之前会在堆栈展开期间调用它。
在某些情况下可能不会被调用,包括:
  • 通过调用longjmp离开;这将导致未定义的行为;
  • 通过未处理的异常离开;未指定是否展开堆栈。
  • 终止程序(例如调用exit或引发导致终止的信号)。

2
是的,析构函数会被调用。如果您提前返回,那么在堆栈上创建的每个对象都将被正确销毁。如果抛出异常,则在程序执行到catch块后才会调用析构函数。

2
这个答案不完整,因此是错误的。从标题可以看出:“如果一个函数崩溃了,对象的析构函数会被调用吗?” - Konrad Rudolph
1
我认为他在谈论异常而不是崩溃。 - Nikita
即使是异常情况,如果代码没有运行在try块中,也不会发生这种情况。 - juanchopanza
抱歉,该代码在更高级别的try块中运行。我会调整标题。 - mr_T

2

除非程序因分段错误、断电或其他原因崩溃,否则将调用析构函数。仅从函数中提前返回或抛出异常是不足以停止析构函数的运行。

尽管如此,这种设计有些缺陷,因为写入数据库是可能失败的操作,从析构函数中抛出异常是一个相当糟糕的想法。


你能建议我如何处理这种情况吗?如果从析构函数中抛出异常会发生什么? - mr_T

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接