为什么有一个特殊的new和删除数组?

Jef*_*ffV 11 c c++ arrays memory-management new-operator

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

在分配和释放数组的过程中是否有一些特殊的事情发生?

为什么它会malloc与免费不同?

Bri*_*ndy 14

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

使用malloc和free,您可以获得更简单的情况.只有一个函数可以释放您分配的数据,也没有任何析构函数被调用的概念.混乱只是因为delete[]和删除看起来相似.实际上它们是两个完全不同的功能.

使用delete不会调用正确的函数来删除内存.它应该调用delete[](void*),而是调用它delete(void*).因此,您不能依赖于使用delete分配的内存new[]

请参阅此C++ FAQ

[16.13]我可以删除删除[]某些内置类型(char,int等)的数组吗?

没有!

有时,程序员认为, []delete[] p只存在这样编译器将调用适当的析构函数数组中的所有元素.由于这个推理,他们假设一些内置类型的数组,例如char或者int可以 delete没有[].例如,他们假设以下是有效代码:

void userCode(int n)  {
    char* p = new char[n];
    ...
    delete p; // ? ERROR! Should be delete[] p !
}
Run Code Online (Sandbox Code Playgroud)

但上面的代码是错误的,它可能会在运行时导致灾难.特别是,所要求的代码 delete poperator delete(void*),但所需的代码 delete[] poperator delete[](void*).后者的默认行为是调用前者,但允许用户用不同的行为替换后者(在这种情况下,他们通常也会替换运算符中的相应新代码new[](size_t)).如果他们替换了delete[]代码,因此它与删除代码不兼容,并且您调用了错误代码(即,如果您说delete p而不是delete[] p),则可能会在运行时遇到灾难.

为什么delete[]首先存在?

无论你做x还是y:

 char * x = new char[100]; 
 char * y = new char;
Run Code Online (Sandbox Code Playgroud)

两者都存储在char *类型变量中.

我认为决定的原因delete,以及delete[]一系列支持C++效率的决策.这样就没有强制价格来查找正常删除操作需要删除多少.

拥有2 newnew[]似乎只有合乎逻辑的有deletedelete[]反正对称.


Jar*_*Par 12

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

编辑更新

根据标准,传递分配有new[]to 的对象delete是未定义的.在可能的行为是因为我描述它会采取行动.


And*_*ant 5

这个要求的原因是历史性的,因为new typenew type [size]返回不同的东西,需要以不同的方式清理。

考虑这个代码

Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];
Run Code Online (Sandbox Code Playgroud)

它们都返回一个Foo*指针,不同之处在于第二次调用将导致 Foo 构造函数被调用 10 倍,内存大约是 10 倍。

所以现在你想释放你的对象。

对于单个对象,您将调用 delete-eg delete oneEntry。这会调用对象的析构函数并释放内存。

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

当您使用delete []. 这告诉编译器“这是一个对象数组,计算出计数然后将它们全部销毁”。

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

然后你可以问的问题是“为什么编译器不总是存储大小?”

这是一个很好的问题,它可以追溯到 C++ 的早期。对于内置类型(char、int、float 等),希望以下内容对 C++ 有效;

int* ptr = new int;
free(ptr);

int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;
Run Code Online (Sandbox Code Playgroud)

这背后的原因是期望人们会提供返回动态分配内存的库,而这些库的用户将无法知道是否使用 free/delete。

这种对兼容性的渴望意味着数组的大小不能作为数组本身的一部分存储,而必须保存在其他地方。由于这种开销(请记住,这是在 80 年代初),因此决定只为数组而不是单个元素保留这本书。因此数组需要一个特殊的删除语法来查找这个值。

之所以malloc/free没有这个问题是他们根本对付的内存块,不必担心调用构造函数/析构函数。


Mic*_*urr 5

关于原因,独立斯特劳斯会谈new/ new[]delete/通过10.5.1删除[]`运营商在部分10.3"的设计和C++的进化":

  • 10.3数组分配 - 讨论了他们想要一种方法来允许使用与分配单个对象分开的单独方案来分配对象数组(即,从单独的存储分配数组).添加数组版本newdelete为此提供解决方案;
  • 10.5.1解除分配数组 - 讨论如何仅使用单个delete运算符解除分配数组的问题是,除了指针之外需要更多信息以确定指针是指向数组的第一个元素还是指向数组到一个对象.delete[]运算符用于处理数组,而不是"使分配和解除分配单个对象的常见情况复杂化" .这符合一般的C++设计哲学"不要为你不使用的东西买单".

这个决定是否是一个错误是有争议的 - 无论哪种方式有充分的论据,但我们拥有我们拥有的.