C++ 为什么阵列有一个特殊的new和delete?

C++ 为什么阵列有一个特殊的new和delete?,c++,arrays,memory-management,new-operator,C++,Arrays,Memory Management,New Operator,使用delete而不是delete[]有什么问题 在分配和释放阵列的掩护下是否发生了一些特殊的事情 为什么它不同于malloc和free?使用new[]创建的对象必须使用delete[]。使用delete在数组上未定义 有了malloc和free,情况就更简单了。只有一个函数释放分配的数据,也没有调用析构函数的概念。这种混淆是因为delete[]和delete看起来很相似。实际上,它们是两个完全不同的函数 使用delete不会调用正确的函数来删除内存。它应该调用delete[](void*),但

使用
delete
而不是
delete[]
有什么问题

在分配和释放阵列的掩护下是否发生了一些特殊的事情


为什么它不同于
malloc
和free?

使用
new[]
创建的对象必须使用
delete[]
。使用
delete
在数组上未定义

有了malloc和free,情况就更简单了。只有一个函数释放分配的数据,也没有调用析构函数的概念。这种混淆是因为
delete[]
和delete看起来很相似。实际上,它们是两个完全不同的函数

使用delete不会调用正确的函数来删除内存。它应该调用
delete[](void*)
,但它会调用
delete(void*)
。因此,对于分配给
new[]

[16.13]我可以在什么时候删除
[]
吗 正在删除某些内置类型的数组 (字符、整数等)

有时程序员认为
delete[]p
中的
[]
编译器将调用适当的
中所有元素的析构函数
数组。因为这个理由,他们
假设某个内置的
可以选择
char
int
等类型
删除
d而不使用
[]
。例如,他们 假设以下代码有效:

void userCode(int n)  {
    char* p = new char[n];
    ...
    delete p; // ← ERROR! Should be delete[] p !
}
但是上面的代码是错误的,而且 在运行时可能导致灾难。在里面 特别是,所调用的代码
delete p
操作员删除(void*)
, 但是需要的代码
delete[]p
运算符
删除[](无效*)
。默认行为 因为后者叫前者, 但允许用户更换 后者具有不同的行为(在 在这种情况下,他们通常也会 替换中相应的新代码 操作员
new[](大小)
)。如果他们 替换了
delete[]
代码,以便 与删除不兼容 密码,你打错电话了 (即,如果您说
删除p
而不是 比删除[]p
),您可能会 在运行时发生灾难

为什么
delete[]
首先存在?

无论您选择x还是y:

 char * x = new char[100]; 
 char * y = new char;
两者都存储在
char*
类型化变量中

我认为,决定“代码>删除删除/代码>,和<代码>删除[]/CODE >是一系列有利于C++效率的决定。这样就没有强制执行的价格来查找正常删除操作需要删除多少


拥有2个
new
new[]
似乎只是为了对称而选择
delete
delete[]
才合乎逻辑

不同之处在于
delete
只会删除整个内存范围,但只会调用一个对象的析构函数
delete[]
将删除内存并为每个对象调用析构函数。如果不对数组使用
delete[]
,那么将资源泄漏引入应用程序只是时间问题

编辑更新


根据标准,将分配有
new[]
的对象传递给
delete
是未定义的。可能的行为是它将按照我所描述的那样行动

> P>使用“代码>新[] /代码>分配数组时,实际上是在告诉C++数组的大小。当您使用
malloc
时,您会告诉它分配了多少内存。在前一种情况下,基于数组大小进行释放是没有意义的。在这种情况下,确实如此。但是,由于数组指针与单个对象指针没有区别,因此需要一个单独的函数。

new
delete
不同于
malloc
free
,因为
malloc
free
只分配和释放内存;它们不调用CTOR或DTOR。

此要求的原因是历史原因,因为
新类型
新类型[大小]
返回需要以不同方式清理的不同内容

考虑一下这个代码

Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];
这两个函数都返回一个
Foo*
指针,不同的是第二次调用将导致Foo构造函数被调用10倍,并且内存大约是原来的10倍

因此,现在要释放对象

对于单个对象,您可以调用delete-例如
delete-oneEntry
。这将调用对象析构函数并释放内存

但问题是,oneEntry和tenEntries都只是
Foo
指针。编译器不知道它们是指向一个、十个还是一千个元素

当您使用特殊语法
delete[]
时。这会告诉编译器“这是一个对象数组,计算出数量,然后将其全部销毁”

真正发生的是,对于
新类型[size]
,编译器将“size”秘密存储在其他地方。调用delete[]时,它知道这个秘密值存在,因此它可以找出该内存块中有多少个对象,并对它们进行销毁

然后您可能会问“为什么编译器不总是存储大小?”

这是个很好的问题,它可以追溯到C++的早期。对于内置类型(char、int、浮点等),有以下的愿望:C++是有效的;p>
int* ptr = new int;
free(ptr);

int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;
这背后的原因是人们希望提供返回动态分配内存的库,而这些库的用户将无法知道是否使用free/delete

这种渴望