为什么不能释放由new分配的内存?

3

我知道free()不会调用析构函数,但是除了成员变量无法正确销毁之外,这还会引起什么问题吗?

另外,如果我们删除使用malloc分配的指针会发生什么?


7
如果我向你借了100万美元(读作:1MB),然后却还给了别人而不是你,你会生气吗?这里有同样的问题,不过现在收款人生气了。 :P - user541686
6个回答

11

2
甚至可以是同一编译器的同一版本,但在蓝月亮期间进行编译 :-) - paxdiablo
甚至是在同一编译会话中,但在不同的代码单元中。或者是相同的代码单元。或者是相同的函数。这就是未定义行为,宝贝! - Jonathan Grynspan
它真的是“实现定义”吗?我本来以为它是未定义的,这与“实现定义”非常不同。 - JesperE
@JesperE:我从未说过行为(总体而言)是实现定义的。它实际上是未定义的。新建使用malloc是实现定义的,这就是我在答案中提到的。 - Prasoon Saurav
@Prasoon:所以编译器必须指定malloc是否使用new?听起来很奇怪。 - JesperE

9

我知道free()不会调用析构函数

这已经足够的理由不去使用它。

此外,C++实现没有要求使用相同的内存区域来进行mallocnew操作,所以你可能试图释放来自完全不同区域的内存,这几乎肯定会导致致命错误。


1
最好的一点。只有在考虑普通数据时才能考虑它。但是为什么要这样做?+1! - 0xC0000022L

4

需要注意的几点:

  • 这是未定义行为,因此存在风险,并且随时可能因任何原因而发生更改或中断。
  • (如您所知)delete 调用析构函数,而 free 不会... 您可能有一些 POD 类型并且不在意,但其他人可能会添加一个字符串到该类型中,而没有意识到其内容存在奇怪的限制。
  • 如果您使用 malloc 并忘记使用放置 new 来构建其中的对象,然后调用成员函数,就好像该对象已存在(包括 delete 调用析构函数),则成员函数可能会尝试使用带有垃圾值的指针进行操作。
  • newmalloc 可能从不同的堆中获取内存。
  • 即使 new 调用 malloc 来获取其内存,也可能不存在 new/delete 与底层 malloc/free 行为之间的一对一对应关系。
    • 例如,new 可能具有额外的逻辑,例如对典型 C++ 程序有益但对典型 C 程序有害的小对象优化。
  • 某人可能会重载 new,或链接调试版本的 malloc/realloc/free,其中任何一种都可能在您未正确使用这些函数时出现故障。
  • 像 ValGrind、Purify 和 Insure 这样的工具无法区分有意的可疑行为和意外行为。
  • 对于数组,delete[] 调用所有析构函数,而 free() 不会,但是堆内存通常具有数组大小的计数器(例如,对于 32 位 VC++2005 发行版,数组大小在指针值明显返回的 4 字节之前)。 对于 POD 类型,可能不存在此额外值(对于 VC++2005 并非如此),但如果存在,则 free() 肯定不会期望它。 并非所有堆实现都允许您释放已从 malloc() 返回的值移动的指针。

2

一个重要的区别是,new和delete还会调用对象的构造函数和析构函数。因此,可能会出现意外的行为。我认为这是最重要的事情。


2

因为可能不是同一个分配器,这可能导致奇怪、难以预测的行为。此外,您根本不应该使用malloc/free,并避免在不必要的情况下使用new/delete。


1

这完全取决于实现方式 - 可以编写一个实现,使其正常工作。但是不能保证new分配内存的池与free()要返回内存的池相同。想象一下,malloc()new在每个分配块的开头使用几个字节的额外内存来指定块的大小。此外,想象一下,malloc()new对此信息使用不同的格式 - 例如,malloc()使用字节数,但new使用4字节长字的数量(仅举例)。现在,如果您使用malloc()进行分配并使用delete进行释放,则delete期望的信息将无效,并且您将得到一个已损坏的堆。


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