通过基类指针销毁派生类实例的UB判定及C++标准疑问
代码1示例
// code1 struct A { int e; }; struct B : A { virtual ~B() { } }; struct C : B { ~C() { } };
类A是平凡可析构的。
Q1:在代码1中,通过类A的指针销毁类C的实例,行为是否为未定义行为(UB)?
是UB。静态类型A没有虚析构函数,且静态类型A与动态类型C不同,不符合delete操作的标准要求,触发未定义行为。
Q2:在代码1中,通过类B的指针销毁类C的实例,行为是否为UB?
不是UB。静态类型B是动态类型C的基类,且B拥有虚析构函数,满足标准规定的条件,析构会正确调用C的析构函数,再依次触发B、A的析构函数,行为定义明确。
代码2示例
//code2 struct A { int e; ~A() { } }; struct B : A { virtual ~B() { } }; struct C : B { ~C() { } };
类A拥有用户提供的析构函数,因此不是平凡可析构的。
Q3:在代码2中,通过类A的指针销毁类C的实例,行为是否为UB?
是UB。静态类型A没有虚析构函数,即使A的析构函数是非平凡的,只要静态类型与动态类型不同且无虚析构函数,就违反标准要求,属于未定义行为。
Q4:在代码2中,通过类B的指针销毁类C的实例,行为是否为UB?
不是UB。静态类型B是C的基类且带有虚析构函数,符合标准规定,析构流程会正确触发C、B、A的析构函数,行为合法。
标准条款参考
In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
——ISO/IEC 14882:2011(E) [expr.delete]/3
Q5:标准中提到“静态类型必须拥有虚析构函数”,那么该静态类型的基类情况如何?
标准只要求当前用于delete的静态类型本身拥有虚析构函数,对该静态类型的基类是否有虚析构函数没有强制要求。只要静态类型满足“是动态类型的基类”且“自身有虚析构函数”这两个条件,就符合标准规则,基类的析构函数是否为虚函数、是否平凡,都不影响当前delete操作的合法性(基类的析构函数会按继承链正常调用)。
内容的提问来源于stack exchange,提问作者iTruth

