我想知道这是否是未定义的行为:
#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的语法
我可以说以上是未定义的行为,对吗?
答案 0 :(得分:22)
是的,行为是不确定的。
传递给delete[]
的指针必须与您从new[]
返回的指针具有相同的类型。
请注意,对于delete
和new
,提交给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)在第一个备选方案(删除对象)中,如果要删除的对象的静态类型不同于其动态类型,则静态类型应为动态对象的基类。要删除的对象的类型和静态类型应具有虚拟析构函数或行为未定义。 在第二种选择(删除数组)中,如果要删除的对象的动态类型与静态类型不同,则行为是不确定的。
请注意,我强调的删除数组案例中没有多态关系的规定;与删除对象情况相反。