为什么是未定义的行为通过基指针删除[]一个派生对象数组? [英] Why is it undefined behavior to delete[] an array of derived objects via a base pointer?

查看:116
本文介绍了为什么是未定义的行为通过基指针删除[]一个派生对象数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 5.3.5 [expr.delete] p3 下找到C ++ 03标准中的以下片段:

I found the following snippet in the C++03 Standard under 5.3.5 [expr.delete] p3:


在第一个替换( delete object )中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为操作数动态类型的基类和静态类型应具有虚析构函数或行为未定义。 如果要删除的对象的动态类型与其静态类型不同,则在第二个替换(删除数组)中,行为是未定义的

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 operand’s dynamic type 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.






快速查看静态和动态类型:


Quick review on static and dynamic types:

struct B{ virtual ~B(){} };
struct D : B{};

B* p = new D();

的静态类型 $ c> B * ,而 * p 的动态类型是 D code> 1.3.7 [defns.dynamic.type] :

Static type of p is B*, while the dynamic type of *p is D, 1.3.7 [defns.dynamic.type]:


[示例:如果指针 p 的静态类型为指向类B 指向一个对象从 B 派生的类D ,表达式的动态类型 * p D 。]

[Example: if a pointer p whose static type is "pointer to class B" is pointing to an object of class D, derived from B, the dynamic type of the expression *p is "D."]






现在,再次查看顶部的引用,这意味着如果我有正确的话,下面的代码调用未定义的行为,不管是否存在 virtual destructor:


Now, looking at the quote at the top again, this would mean that the follwing code invokes undefined behaviour if I got that right, regardless of the presence of a virtual destructor:

struct B{ virtual ~B(){} };
struct D : B{};

B* p = new D[20];
delete [] p; // undefined behaviour here

我误解了标准中的措辞吗?我忽略了什么吗?为什么标准将此规定为未定义的行为?

Did I misunderstand the wording in the standard somehow? Did I overlook something? Why does the standard specify this as undefined behaviour?

推荐答案

Base * p = new Base [n] 创建 n -sized数组 Base 元素,其中 p ,然后指向第一个元素。 Base * p = new Derived [n] 但是,创建 n 派生元素。 p 然后指向第一个元素的 Base 子对象。 p 不会指向数组的第一个元素,这是有效的

Base* p = new Base[n] creates an n-sized array of Base elements, of which p then points to the first element. Base* p = new Derived[n] however, creates an n-sized array of Derived elements. p then points to the Base subobject of the first element. p does not however refer to the first element of the array, which is what a valid delete[] p expression requires.

当然,可以强制(然后实现) delete [] p 在这种情况下是正确的Thing™。但它会需要什么?一个实现必须注意以某种方式检索数组的元素类型,然后在道德上 dynamic_cast p 类型。然后是像我们已经做的那样做一个简单的 delete []

Of course it would be possible to mandate (and then implement) that delete [] p Does The Right Thing™ in this case. But what would it take? An implementation would have to take care to somehow retrieve the element type of the array, and then morally dynamic_cast p to this type. Then it's a matter of doing a plain delete[] like we already do.

问题是,这将需要每次多态元素类型的数组,而不管是否使用多态性。在我看来,这不符合C ++的哲学,不支付你不使用的东西。但是更糟糕的是:一个多态的 delete [] p 根本没用,因为 p 在你的问题中几乎没用。 p 是指向元素的子对象的指针,不再是;否则它与数组完全无关。你当然不能用它来做 p [i] i> 0 )。因此, delete [] p 不起作用并非不合理。

The problem with that is that this would be needed every time an array of polymorphic element type, regardless of whether the polymorphism is used on not. In my opinion, this doesn't fit with the C++ philosophy of not paying for what you don't use. But worse: a polymorphic-enabled delete[] p is simply useless because p is almost useless in your question. p is a pointer to a subobject of an element and no more; it's otherwise completely unrelated to the array. You certainly can't do p[i] (for i > 0) with it. So it's not unreasonable that delete[] p doesn't work.

总结: / strong>

To sum up:


  • 阵列已经有很多合法用途。通过不允许数组以多态方式(整体或仅用于 delete [] ),这意味着具有多态元素类型的数组不会对那些合法用途符合C ++的哲学。

  • arrays already have plenty of legitimate uses. By not allowing arrays to behave polymorphically (either as a whole or only for delete[]) this means that arrays with a polymorphic element type are not penalized for those legitimate uses, which is in line with the philosophy of C++.

如果另一方面需要一个具有多态行为的数组,那么可以实现一个已经。

if on the other hand an array with polymorphic behaviour is needed, it's possible to implement one in terms of what we have already.

这篇关于为什么是未定义的行为通过基指针删除[]一个派生对象数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆