Base pointer to array of derived objects

旧街凉风 提交于 2019-11-27 05:05:49

If you look at the expression p[1], p is a Base* (Base is a completely-defined type) and 1 is an int, so according to ISO/IEC 14882:2003 5.2.1 [expr.sub] this expression is valid and identical to *((p)+(1)).

From 5.7 [expr.add] / 5, when an integer is added to a pointer, the result is only well defined when the pointer points to an element of an array object and the result of the pointer arithmetic also points the an element of that array object or one past the end of the array. p, however, does not point to an element of an array object, it points at the base class sub-object of a Derived object. It is the Derived object that is an array member, not the Base sub-object.

Note that under 5.7 / 4, for the purposes of the addition operator, the Base sub-object can be treated as an array of size one, so technically you can form the address p + 1, but as a "one past the last element" pointer, it doesn't point at a Base object and attempting to read from or write to it will cause undefined behavior.

(3) leads to undefined behaviour, but it is not ill-formed strictly speaking. Ill-formed means that a C++ program is not constructed according to the syntax rules, diagnosable semantic rules, and the One Definition Rule.

Same for (2), it is well-formed, but it does not do what you have probably expected. According to §8.3.4/6:

Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)). Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its asymmetric appearance, subscripting is a commutative operation.

So in (2) you will get the address which is the result of p+sizeof(Base)*1 when you probably wanted to get the address p+sizeof(Derived)*1.

The standard doesn't disallow (2), but it's dangerous nevertheless.

The problem is that doing p[1] means adding sizeof(Base) to the base address p, and using the data at that memory location as an instance of Base. But chances are very high that sizeof(Base) is smaller than sizeof(Derived), so you'll be interpreting a block of memory starting in the middle of a Derived object, as a Base object.

More information in C++ FAQ Lite 21.4.

p[1].member = 42; 

is well formed. Static type for p is Derived and dynamic type is Base. p[1] is equivalent to *(p+1) which seems a valid and is a pointer to first element of dynamic type Base in array.

However, *(p+1) in fact refers to an array member of type Derived. Code p[1].member = 42; shows you think you are referring to an array member with type Base.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!