繁体   English   中英

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

[英]Is delete and delete[] equivalent for basic data types

所以在代码审查期间,我的一位同事使用了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编译器的怪癖吗? 或者这是标准的一部分?

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

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

他们的意思不同。 double* d = new double(); 意味着分配和构造一个double类型。 delete d; 表示未分配并破坏单个双重类型。 double* d = new double[NUM_VALUES]; 表示分配NUM_VALUES双精度数并delete [] d表示未分配的每个NUM_VALUES双精度分配。

我告诉他们应该改变它以delete [] d

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

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

对于“单个对象”和“数组”分配,实现很可能从同一位置获取内存,在这种情况下,使用错误形式的delete将显得有效。 释放内存然后分配相同的数量也很可能重用相同的内存。 但是,这并不是标准所保证的。

在你的分歧中你是完全正确的。

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

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

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

首先,这个问题的接受答案是删除vs delete []引用标准,说行为是未定义的。 这应该满足你的同事。 这里有更多讨论: delete []是否等于delete?

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

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

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

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

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

事实上,这是特定实现的行为方式并不是依赖该行为的理由。

主要的原因代码是容易出问题的一些实施,地方,如果是new[]分配的数组加上空间大小的空间,并返回一个指针数组。 delete[]然后会在释放分配之前减去用于大小的空间,而delete不会。 你的同事选择打赌永远不会遇到使用new double[]执行此操作的实现。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM