该标准区分了抛出异常时发生的两种破坏形式.强调我的.
§15.2/ 1
当控制从throw-expression传递到处理程序时,将为输入try块后构造的所有自动对象调用析构函数.自动对象按照完成构造的相反顺序销毁.
§15.2/ 2
任何存储持续时间的对象,其初始化或销毁由异常终止,将为其所有完全构造的子对象(不包括类似联合的类的变体成员)执行析构函数,即对于其主要构造函数的子对象( 12.6.2)已完成执行并且析构函数尚未开始执行.类似地,如果对象的非委托构造函数已完成执行并且该对象的委托构造函数以异常退出,则将调用该对象的析构函数.如果对象是在new-expression中分配的,则调用匹配的释放函数(3.7.4.2,5.3.4,12.5)(如果有)以释放对象占用的存储空间.
§15.2/ 3
为从try块到throw-expression的路径构造的自动对象调用析构函数的过程 称为" 堆栈展开"."如果在堆栈展开期间调用的析构函数以异常退出,
std::terminate则调用(15.5.1).[ 注意:因此析构函数通常应该捕获异常,而不是让它们从析构函数中传播出来.- 结束说明 ]
因此,似乎我们有(a)堆栈展开,它会破坏自动对象,以及(b)破坏构造函数或析构函数通过异常退出的对象的完全构造的子对象,无论存储持续时间如何都会发生.
仔细阅读§15.2/ 1表明,只有当控制传递给处理程序时,才会发生堆栈展开,如果未处理异常,则可能会发生堆栈展开的可能性.的确,§15.5.2/ 2说,
在没有找到匹配处理程序的情况下,无论堆栈是否在
std::terminate()被调用之前被展开,它都是实现定义的."
但是§15.2/ 2的措辞似乎没有留下这种可能性.它只是说初始化或破坏必须由异常终止 - 而不是控件必须传递给处理程序.所以我的解释是,即使没有处理异常,子对象仍然被销毁.这是正确的解释吗?
例如,假设我们有
std::vector<int> V;
ComplicatedObject* p = new ComplicatedObject();
Run Code Online (Sandbox Code Playgroud)
并且它ComplicatedObject的构造函数抛出,并且不处理异常.然后是否V被销毁是实现定义的.它是否也是实现定义的,是否*p销毁了完全构建的子对象?请注意,此类对象没有自动存储持续时间.