删除和删除[]等效于基本数据类型

时间:2013-11-21 16:42:44

标签: c++ delete-operator

因此,在代码审核过程中,我的一位同事使用了double* d = new double[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;
}

不仅内存使用量不增长,而且每次都将d分配到同一个地方! (Visual Studio 2010)。这是visual studio编译器的怪癖吗?或者这是标准的一部分吗?

5 个答案:

答案 0 :(得分:10)

如果您使用new,则需要使用delete

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

它们意味着不同的东西。 double* d = new double();表示分配和构造double类型。 delete d;表示未分配并破坏单个双精度类型。 double* d = new double[NUM_VALUES];表示分配NUM_VALUES双打,而delete [] d表示已分配的NUM_VALUES双打中的每一个都未分配。

答案 1 :(得分:5)

  

我告诉他们应该将其更改为delete [] d

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

  

这是visual studio编译器的怪癖吗?或者这是标准的一部分吗?

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

答案 2 :(得分:1)

你的分歧绝对正确。

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

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

所有这些甚至都没有提到在语言层面上这些机制使用的原始内存分配函数(operator new()函数和其余函数)是可以独立替换的,这意味着即使这些运算符的轻率混合似乎对于实现中的基本类型,“工作”,可以通过原始内存分配替换轻松打破它。

答案 3 :(得分:1)

首先,这个问题delete vs delete[]的接受答案引用了标准,称行为未定义。这应该满足你的同事。这里有更多的讨论:Is delete[] equal to delete?

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

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

然而,因为我是旧时的C ++呃,我知道你的同事混乱的根源。考虑new/deletenew[]/delete[]使用C malloc/free进行后端和直接调用构造函数/析构函数的最简单实现。很容易看出,对于一个简单的实现,正如原始的C ++实现一样,deletedelete[]对于没有析构函数的类型是等价的。围绕着这种情况已经形成了某种民间传说,这可能是你同事声明的来源,但它并没有在现实中占据,事实上也从未如此。

答案 4 :(得分:1)

作为参考,它似乎有效的原因在于您的实施:

  • 他们都从同一来源获取记忆
  • 作为优化,对于double(可能是其他一些类型),new[]不会使用存储所请求的数组大小的任何内存。对于具有析构函数的类型delete[]需要知道要销毁多少对象,因此必须将该大小存储在某处。

这就是特定实现的行为方式,是依赖该行为的理由。

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

这个必要的数字 not 总是可以由非标准函数(如malloc_size()返回的值)推断出C ++实现,因为它返回用于满足分配,而不是要求的大小。因此,通常人们应该期望new[]delete[]使用某种技巧或其他技巧,而这纯粹是实现质量的问题,这是他们为此避免的类型。

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