struct Base { int member; }; struct Derived : Base { int another_member; }; int main() { Base* p = new Derived[10]; // (1) p[1].member = 42; // (2) delete[] p; // (3) }
根据标准(1)是格式正确的,因为Dervied *(这是新表达式的结果)可以隐式转换为Base *(C11草案,§4.10/ 3):
A prvalue of type “pointer to cv D”,where D is a class type,can be
converted to a prvalue of type “pointer to cv B”,where B is a base
class (Clause 10) of D. If B is an inaccessible (Clause 11) or
ambiguous (10.2) base class of D,a program that necessitates this
conversion is ill-formed. The result of the conversion is a pointer to
the base class subobject of the derived class object. The null pointer
value is converted to the null pointer value of the destination type.
(3)由于§5.3.5/ 3导致未定义的行为:
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.
(2)是否符合标准,否则会导致程序不合格或未定义的行为?
编辑:更好的措辞
解决方法
从5.7 [expr.add] / 5,当一个整数被添加到一个指针时,结果只有在指针指向数组对象的元素并且指针算术的结果也指向该元素数组对象或数组的末尾. p然而,并不指向数组对象的元素,它指向Derived对象的基类子对象. Derived对象是数组成员,而不是Base子对象.
请注意,在5.7 / 4以下,对于加法运算符,Base子对象可以被视为大小为1的数组,因此在技术上您可以形成地址p 1,但是作为“一个最后一个元素”指针,它不指向一个Base对象,并尝试读取或写入它将导致未定义的行为.