C++ 对于基本数据类型,delete和delete[]是否等效

C++ 对于基本数据类型,delete和delete[]是否等效,c++,delete-operator,C++,Delete Operator,所以在一次代码审查中,我的一位同事使用了一个double*d=newdouble[foo]然后调用delete d。我告诉他们应该把它改成delete[]d。他们还说,编译器不需要对基本数据类型使用它。我不同意 所以我想用一个实验来证明我的观点: #define NUM_VALUES 10000 int main(int argc,char** argv) { int i = 0; while (true) { std::cout << i << "|

所以在一次代码审查中,我的一位同事使用了一个
double*d=newdouble[foo]
然后调用
delete d
。我告诉他们应该把它改成
delete[]d
。他们还说,编译器不需要对基本数据类型使用它。我不同意

所以我想用一个实验来证明我的观点:

#define NUM_VALUES 10000
int main(int argc,char** argv)
{
  int i = 0;
  while (true)
  {
    std::cout << i << "|";
    double* d = new double[NUM_VALUES];
    std::cout << ((void*)d) << std::endl;
    for (int j = 0; j < NUM_VALUES; j++)
      d[j] = j;

    delete d;
    i++;
  }

  return 0;
}
#定义数值10000
int main(int argc,字符**argv)
{
int i=0;
while(true)
{

std::cout如果使用
new
则需要使用
delete

如果使用
new[]
则必须使用
delete[]

它们的含义不同。
double*d=new double();
表示分配并构造一个double类型。
delete d;
表示未分配并销毁一个double类型。
double*d=new double[NUM_值];
表示分配
NUM_值
doubles和
delete[]d
表示未分配的每个
NUM\u值
双倍分配

我告诉他们应该把它改成
delete[]d

你是对的。使用错误的
delete
形式会导致未定义的行为

这是VisualStudio编译器的一个怪癖吗?还是标准的一部分


一个实现很可能会从同一个位置获取“单个对象”和“数组”的内存分配,在这种情况下,对普通类型使用错误形式的
delete
似乎会起作用。释放内存然后分配相同数量的内存也很可能会重用相同的内存。不过,这些都不是标准所保证的。

你的意见绝对正确

正如已经多次指出的那样,
new/delete
new[]/delete[]
是两种独立的、完全独立的动态内存管理方式。它们不能混合使用(如对
new[]
分配的内存使用
delete
),无论使用哪种类型

这两种机制在物理上很容易不同,即它们可以使用完全不同的内存布局、完全不同的内存池,甚至可以使用完全不同类型的系统级内存


所有这些都没有提到,在语言级别上,这些机制使用的原始内存分配函数(
operator new()
函数和其他函数)是可独立替换的,这意味着即使这些运算符的不经考虑的混合似乎“起作用”对于实现中的基本类型,它很容易被原始内存分配替换破坏。

首先,此问题的公认答案引用了标准,表示行为未定义。这应该让您的同事满意。这里有更多讨论:

如果他不相信,您可以提醒他全局
new/delete
,以及全局
new[]/delete[]
可以在这些对中被覆盖,因此即使
new[]/delete
对(对于基本类型)在VS2010实现DoNoCrash中,绝对不能保证另一个实现不会失败

例如,我们在调试模式下覆盖了全局
new[]/delete[]
,以隐藏“数组结束标记”以验证使用情况。我们当然希望在使用
new[]
创建的双精度数组上调用
delete[]
,这样才能工作


然而,因为我是老C++er,我知道你的同事们困惑的根源。想想
new/delete
new[]/delete[]使用C的代码> MalC/Cube < /Cube >后端并直接调用构造函数/析构函数。很容易看出,对于一个简单的实现,正如原始C++实现的那样,<代码>删除< /C>和<代码>删除[]。
对于没有析构函数的类型是等效的。围绕这一点已经形成了某种民间传说,这可能是您同事声明的来源,但它在现实中并不成立,事实上从未成立过。

作为参考,它似乎起作用的原因是在您的实现中:

  • 他们都是从同一个来源获得记忆的
  • 作为优化,对于
    double
    (可能还有一些其他类型)
    new[]
    不使用任何内存来存储请求的数组大小。对于具有析构函数的类型
    delete[]
    需要知道要销毁多少对象,因此必须将大小存储在某个位置
事实上,这就是特定实现的行为方式,并不是依赖该行为的好理由

代码在某些实现中可能出错的主要原因是
new[]
为数组分配空间加上大小空间,并返回指向数组的指针。
delete[]
然后会在释放分配之前减去用于大小的空间,而
delete
则不会。您的同事已选择打赌,在
new double[]中不会遇到这样的实现

<>这个必要的数字不能总是由C++实现从非标准函数如<代码> MalCuxsie()/Cube返回的值中推导出来,因为它返回了用于满足分配的块的大小,而不是所请求的大小。因此一般应该期待<代码> NeX[]/Calp>和<代码> Dele[]
使用一些技巧或其他技巧,而这纯粹是实现质量的问题,他们避免使用哪种类型


即使这个实现足够聪明,可以避免使用一个
double
数组需要额外的空间,它也可能有一个调试模式,故意检测错误。

我同意你的观点,安德烈,对此没有异议。但是,这并不能解释为什么我的实验没有爆炸。是因为行为没有定义吗?@MaD科学流