在C++中,如果构造函数抛出异常,那么运行哪些析构函数?
特别地,在初始化列表或函数体中抛出异常是否有任何区别?
此外,继承和成员变量又如何处理?假设所有已完成的构造都会被析构,如果只构造了一些成员变量,则只有这些成员变量会被析构吗?如果是多重继承,所有已完成的构造函数都会被析构吗?虚拟继承是否有所不同?
在C++中,如果构造函数抛出异常,那么运行哪些析构函数?
特别地,在初始化列表或函数体中抛出异常是否有任何区别?
此外,继承和成员变量又如何处理?假设所有已完成的构造都会被析构,如果只构造了一些成员变量,则只有这些成员变量会被析构吗?如果是多重继承,所有已完成的构造函数都会被析构吗?虚拟继承是否有所不同?
如果构造函数抛出异常,哪些析构函数会运行?
在该作用域中完全创建的所有对象的析构函数。
如果异常发生在初始化列表或主体期间,是否有区别?
所有已完成的对象都将被销毁。
如果构造函数从未完全调用,则对象从未构建,因此无法销毁。
继承和成员变量呢?可以想象只有完成的构建才会被销毁。如果只有一些成员被构造,那么只有这些成员被销毁吗?如果有多重继承,所有已完成的构造函数是否都被销毁?虚拟继承是否会改变情况?
所有已完成的构建都会被销毁。是的,只有完全创建的对象才会被销毁。
好文章:
Constructor Failures by Herb Sutter
特别是他解释的部分:
从生物学角度来看,受孕发生了——构造函数开始了——但尽管做了最大的努力,却随之发生了流产——构造函数从未运行到结束(termination)。
顺便说一下,这就是为什么如果构造函数没有成功,析构函数永远不会被调用——因为没有东西可以销毁。“它不能死亡,因为它从未活过。”请注意,这使得“其构造函数抛出异常的对象”这个短语真正成为了一个自相矛盾的词。这样的事物甚至还不如一个前对象......它从来没有生存过,从未存在过,从未呼吸过第一口气。
任何在局部作用域中因构造函数而创建的对象都将被销毁。运行时处理程序沿着调用栈向上回溯,调用析构函数,直到找到处理程序。
如果异常是从构造函数中抛出的,则将调用所有完全构造的子对象的析构函数。此外,如果构造函数是new
表达式的一部分,则如果存在相应的放置删除运算符,将调用该运算符。