绝对不要以多态方式处理数组(More Effective c++),它说的是处理数组的时候,原因是有指针偏移量的运算,所以Derived类的内容被当成Base类的内容使用的时候,计算出来的偏差是不正确的,所以,本人用VC做了一个实验:
struct B{ int i = 2; virtual ~B(){ cout << "B dtor\n"; } }; struct D :B{ int j = 3; int k = 4; int l = 5; ~D(){ cout << "D dtor\n"; } }; void f(B* pb,size_t s) { for (size_t i = 0; i < s; ++i) cout << pb[i].i << endl; } int main() { B* pb = new D; delete pb; B* p2 = new D[2]; f(p2,2); D buf[2]; f(buf, 2); delete[] p2; return 0; }
VC运行良好,但GCC测试了一下这个程序,然后在delete[]的时候崩溃了,为什么?
解决方案
20
怎么申请就怎么释放,申请是new D,释放时delete[] (D*)p2
10
输出的结果都是错误的,怎么叫运行良好?
10
标准说这叫为定义行为,崩不崩溃都行,不要依赖这样的行为。
70
5.7 5
When an expression that has integral type is added to or subtracted from a pointer, the result has the type
of the pointer operand. If the pointer operand points to an element of an array object, and the array is
large enough, the result points to an element offset from the original element such that the difference of
the subscripts of the resulting and original array elements equals the integral expression. In other words, if
the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P))
and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array
object, provided they exist. Moreover, if the expression P points to the last element of an array object,
the expression (P)+1 points one past the last element of the array object, and if the expression Q points
one past the last element of an array object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements of the same array object, or one past
the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is
undefined.
5.17 8
If the value being stored in an object is accessed from another object that overlaps in any way the storage of
the first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the
behavior is undefined. [ Note: This restriction applies to the relationship between the left and right sides of
the assignment operation; it is not a statement about how the target of the assignment may be aliased in
general. See 3.10. — end note ]
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.
When an expression that has integral type is added to or subtracted from a pointer, the result has the type
of the pointer operand. If the pointer operand points to an element of an array object, and the array is
large enough, the result points to an element offset from the original element such that the difference of
the subscripts of the resulting and original array elements equals the integral expression. In other words, if
the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P))
and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array
object, provided they exist. Moreover, if the expression P points to the last element of an array object,
the expression (P)+1 points one past the last element of the array object, and if the expression Q points
one past the last element of an array object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements of the same array object, or one past
the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is
undefined.
5.17 8
If the value being stored in an object is accessed from another object that overlaps in any way the storage of
the first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the
behavior is undefined. [ Note: This restriction applies to the relationship between the left and right sides of
the assignment operation; it is not a statement about how the target of the assignment may be aliased in
general. See 3.10. — end note ]
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.