【问题标题】:Why is there a delete[] in C++?为什么 C++ 中有一个 delete[]?
【发布时间】:2010-09-12 09:26:24
【问题描述】:

为什么会有delete[]?据我了解,它对数组的行为不同。然而,它为什么真的存在呢? C中只有free,没有free_array。同样在语法上,delete vardelete []var 之间的唯一区别是 [] 没有参数(我没有告诉数组的长度)。

那么为什么delete[] 真的存在呢?我知道有人会说你可以超载deletedelete[](至少我认为这是可能的)但是可以说我们没有超载它。为什么会存在?

【问题讨论】:

  • delete[] 的明显原因是它将调用数组元素的析构函数。见stackoverflow.com/questions/659270/…
  • @jamesdlin:因为我们并不总是有std::vector?因为std::vector 没有它们就无法工作?
  • 并且因为 C++ 语言允许用户自己实现std::vector 的行为,或者更有可能与std::vector 相似但在某些有用方式上有所不同的其他东西。该语言旨在支持低级和专门的开发。
  • @Oli Charlesworth:但是您可以使用 realloc 和放置 new 而不是 new[] 来实现 std::vector(这将支持就地重新分配内存)。
  • 实际上,我意识到如果需要移动内存,realloc 将不起作用,因为没有机会进行适当的复制构造和销毁。尽管如此,还是有mallocfree,而std::vector 无论如何都不会直接使用new[];它使用指定的分配器。

标签: c++ delete-operator


【解决方案1】:

通常,对于非 POD 类,delete[] 表达式必须在编译时无法确定的可变数量的类实例上调用析构函数。编译器通常必须实现一些运行时“魔术”,可用于确定要销毁的正确对象数量。

delete 表达式不必担心这一点,它只需销毁提供的指针指向的一个对象。因此,它可以有一个更有效的实现。

通过拆分deletedelete[],可以实现delete,而无需正确实现delete[] 所需的开销。

【讨论】:

  • 什么?有人可以举个例子说明在编译时无法确定析构函数的数量吗?
  • @Ivella:这个函数怎么样:void freearray(Type* x) { delete[] x; }
  • 和 new[] 通常将对象的数量放在内存的开头——虽然你总是可以在运行时计算大小,但我想这是一个时间/空间的权衡
  • @lvella 获取对象的个数,我们需要:sizeof(allocation)/sizeof(Type),而sizeof(allocation)由heapmanager存储在别处,你必须在运行时获取, 不是编译时间
【解决方案2】:

如果你删除一个数组,只有第一个对象的析构函数会被调用。 delete[] 调用数组中所有对象的析构函数并释放数组的内存。

【讨论】:

  • 如果您delete 某事是new xxx[N] 的结果,您会得到未定义的行为。仅对第一个对象调用析构函数只是一种可能的结果。
【解决方案3】:

假设 delete[] 不存在,编写删除数组的代码 vs 只删除数组中的第一个元素。

delete array;        // Deletes first element, oops    
delete &array;       // Deletes first element, oops
delete &array[0];    // Deletes first element

指向数组的指针是指向数组第一个元素的指针的别名当然是旧的 C“特性”。

【讨论】:

  • @stakx:它没有证明delete[]需要,因此 - 实现可以以某种方式标记分配是否是数组,就像它目前一样跟踪使用new[] 进行的所有分配的长度。然后delete 可以检查标志并做正确的事情。删除数组的第一个元素总是错误的,因此不需要语法。
  • @Steve:这需要运行时测试,而 C++ 通常会尽可能避免这种情况。
  • @Hans:我不明白你的意思。 vector::operator[] 与删除任何内容有什么关系?我的抱怨是你说过,“编写删除数组的代码与[无效的东西]”。谁在乎代码看起来如何做一些无效的事情?在我们想象的 C++ 版本中,delete array表示,“删除整个数组”,并且没有办法说,“删除第一个元素”。 vector 使用显式调用析构函数来销毁元素,因此不受影响。
  • @Steve:抱歉,我不知道您正在考虑 C++ 语言的虚构版本。我的答案是基于真实的,即继承了损坏的 C 数组的那个。
  • @Hans:当您说“假设 delete[] 不存在”时,您开始考虑 C++ 语言的虚构版本,我继续说道。如果您不愿意考虑假设,您可能不应该尝试通过矛盾来证明;-) 显然,如果您假设 delete[] 不存在,那么 delete 将是删除数组的方法。它可以很容易地工作,尽管正如迈克所说,我的标志实现的成本将是运行时检查以区分数组和“普通对象”。或者对象可能只是大小为 1 的数组,也需要一个分支。
【解决方案4】:

考虑:

int* a = new int[25];
int* b = a;

delete b;  // only deletes the first element

C++ 编译器不知道 b 是指向数组还是单个元素。对数组调用 delete 只会删除第一个元素。

【讨论】:

  • 公平地说,delete [] b 也可以这样说;它怎么知道数组中有 25 个项目?答案是幕后的元信息。原则上,编译器还可以在此元信息中存储布尔数组/非数组标志。我认为查尔斯的回答是真正的原因。
  • 即使是普通的delete 也需要元信息才能将内存释放回堆,例如指向前一个和下一个分配块的指针或类似的东西(很大程度上取决于实现)。
  • deletedelete[] 的原因是编译器知道您是要删除该块还是整个数组。
猜你喜欢
  • 2012-06-15
  • 2021-08-07
  • 2010-11-18
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 2019-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多