delete []具有不同类型的未定义行为?

时间:2018-09-26 07:00:52

标签: c++

我想知道这是否是未定义的行为:

#include <stdint.h>

int main() {
  auto* p = new uint8_t[32];
  float* c = reinterpret_cast<float*>(p);
  delete[] c;
}

standard中 有

  

如果不是,则行为未定义。在第二个替代方案(删除数组)中,删除操作数的值可以是空指针值,也可以是由先前数组new-expression产生的指针值。79如果不是,则行为不确定。 [注意:这意味着delete-expression的语法必须与new分配的对象的类型匹配,而不与new-expression的语法匹配。 —尾注]

所以解释有点不清楚的短语

  

这意味着delete-expression的语法必须与new分配的对象的类型匹配,而不是new-expression的语法

我可以说以上是未定义的行为,对吗?

3 个答案:

答案 0 :(得分:22)

是的,行为是不确定的。

传递给delete[]的指针必须与您从new[]返回的指针具有相同的类型。

请注意,对于deletenew,提交给delete的指针可以通过多态关联。

答案 1 :(得分:5)

是的,代码确实存在未定义的行为。措辞意味着当您将其重写为

时,它仍然是UB。
int main() {
  void* p;
  {
     using T = uint8_t;
     p = new T [32];
  }
  {
    using T = float;
    T* c = reinterpret_cast<float*>(p);
    delete[] c; // The behaviour is still undefined.
  }
}

IOW,类型实际上必须完全匹配,而不仅仅是名称上。

答案 2 :(得分:4)

如果delete[] p;的类型与p返回的类型不同,则调用new[]是不确定的行为

值得注意的是:

struct Base { virtual ~Base() = default; };
struct Derived: Base { int a; };

int main() {
    Base* p = new Derived[5];
    delete[] p;
}

也是 未定义的行为。


@Justin在评论see it here中提供了相关的标准报价:

  

5.3.5 [expr.delete]

     

(3)在第一个备选方案(删除对象)中,如果要删除的对象的静态类型不同于其动态类型,则静态类型应为动态对象的基类。要删除的对象的类型和静态类型应具有虚拟析构函数或行为未定义。 在第二种选择(删除数组)中,如果要删除的对象的动态类型与静态类型不同,则行为是不确定的。

请注意,我强调的删除数组案例中没有多态关系的规定;与删除对象情况相反。