指向新元素的指针和新数组有什么区别?

17

在C ++中,下面代码中的指针p和q之间有什么区别吗?

int* p = new int;
int* q = new int[5];

我知道第一个分配新内存给单个int,第二个分配内存给5个int的数组。但是,指向单个int和指向int数组的指针之间是否有任何根本区别呢?

我产生了这个疑问是因为我读到必须使用delete[]q释放由q指向的内存,但仅使用delete p释放由p指向的单个int。如果我使用delete q会发生什么?


1
口语不太严谨,delete 并不会对指针本身产生太大影响,而是针对它所指向的内容进行删除。删除一个 int 不同于删除一个整数数组。 - 463035818_is_not_a_number
2
一些实现会在返回指针之前跟踪数组分配的大小。这是标准未定义的实现细节。但是,您必须记住使用正确的delete形式。 - drescherjm
@drescherjm,您的回答比当前的回答更详细,如果可以,请将其编写为答案,以便我可以将其标记为已接受并关闭问题。 - strider0160
@strider0160,提醒一下,当您接受一个答案时,问题并不会被“关闭”。新的答案仍然可以被添加,这是一件好事。此外,您有可能在以后改变主意并接受不同的答案。 - 463035818_is_not_a_number
两个指针都指向一个int,但其中一个int也恰好是数组的第一个元素。指向五个int数组的指针的类型为int (*)[5] - molbdnilo
显示剩余2条评论
3个回答

18

指针本身是完全无法区分的。这就是为什么必须记得匹配new/deletenew[]/delete[]的原因。

不匹配它们会触发未定义行为。


5

使用 new [] 时,一些 c++ 实现会在返回指针之前的地址中跟踪数组分配的大小。这是一个未被标准定义的实现细节。

下面的答案更详细地描述了这种可能的实现:如何将 new[] 与 delete 配对可能导致仅内存泄漏?

您必须始终将 newdelete 以及 new []delete [] 匹配。混合使用它们是未定义行为。


这是显然错误的,标准规定指针之间存在多个差异,将它们混淆会导致未定义行为。真正的情况是,实现没有义务在程序员忘记差异时通知他们。 - Konrad Rudolph

2
在下面的代码中,指针p和q有什么区别吗?
这些指针之间没有明显的区别,但是它们确实存在且很重要。其中一个是指向整数的指针,而另一个是指向整数的指针,也是给定大小数组中的第一个元素。
不幸的是,只有指针是无法判断的。
如果我使用delete q会发生什么?
可能什么也不会发生,但也可能会发生很多事情。
首先,调用delete而不是delete[]将仅在数组的第一个元素上调用析构函数,而不是在每个元素上调用。现在,对于像int这样的平凡类型,析构函数不做任何事情,所以就这一点而言,没有真正的区别。然而,对于那些具有实际作用的析构函数(或析构函数链)的不太平凡的类型,存在巨大的区别。
其次,您正在干扰底层原始内存块的适当释放。这可能会(有时会)导致硬崩溃。它甚至可能会在稍后的时间,在不相关的、无辜的代码中引起崩溃,由于早期的破坏。尝试进行调试。
或者,您可能会得到一个静默的内存泄漏,这取决于实现,有时甚至取决于您在特定情况下的“运气”(例如是否命中页面边界)。
因为,好吧,分配和释放数组以及分配和释放单个元素并不是相同的事情。它们(通常)被略微不同地实现,虽然实现可能能够处理不匹配的new/delete,但这并不保证。您可能会在调试器中得到与正常执行不同的行为,任何事情都有可能发生。
调用错误形式的delete意味着调用未定义的行为。这基本上意味着任何事情都可能发生。这包括“什么也没有”以及“无法调试的问题”。它还包括编译器恶意优化或剥离整个周围函数的可能性,或者假设某个条件始终为真。这可能导致非常令人讨厌的惊喜,您需要花费数天时间来弄清楚发生了什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接