使用new分配的内存,在调用free()释放时是否安全?

8
我正在开发一个C++库,其中一个函数返回一个(刚刚分配的)指向双精度数组的指针。API规定调用者有责任释放内存。

但是,这个C++库曾经是用C实现的,所以该函数使用malloc()来分配内存。它还假设调用者将使用free()释放该内存。

我能否安全地将对malloc()的调用替换为对new的调用?如果这样做,现有客户端代码(使用free()的代码)会出现问题吗?到目前为止,我找到的只有free()的官方文档,其中指出:

如果ptr不指向使用[malloc、calloc或realloc]分配的内存块,则会导致未定义的行为。

但我相信这是在C++出现其自己的分配运算符之前编写的。


7
不。这真的取决于图书馆,但通常不会。 - thang
4
文件记录是准确的。这是未定义的行为。 - Benjamin Lindley
对于一个double数组,在实践中它是“大多数情况下安全”的,尽管当然仍然是错误的并引发UB。我说“大多数”是因为在实践中,操作符new和delete只是包装了malloc和free,并调用构造函数和析构函数。double上的析构函数是微不足道的,所以没有区别。但是当然,您不能保证在您的实现中使用mallocfree...也可能是其他东西。最好的情况是库提供一个函数来分配和取消分配内存(包装正确的内容)。没有这样的东西? - Damon
通常,释放由另一个模块分配的内存是不好的做法。分配/释放内存的责任应该由调用者或被调用者承担。这背后的思想是,如果您将这些模块链接到不同的CRT,则基本上在一个堆上分配内存,然后尝试在另一个堆上释放它。当模块静态链接到CRT时会发生这种情况。 - Alin
引用C++ faq的话,“使用free()释放通过new分配的指针或者使用delete释放通过malloc分配的指针是非法、不道德和卑鄙的。” - Arjun Sreedharan
6个回答

19

你必须将对 malloc 的调用与 free 相匹配,并将对 new 的调用与 delete 相匹配。混合/匹配它们是不可行的。


2
并且要将 new[]delete[] 匹配。 - osgx

8
你不允许混用mallocfreenewdelete,草案C++标准回溯到C99标准,而如果我们转到draft C++ standard20.6.13 C库中,它说(往后强调我的话):

其内容与标准C库头文件stdlib.h相同,以下是更改内容:

和:

calloc()、malloc()和realloc()函数不尝试通过调用::operator new() (18.6)分配存储空间。

和:

free()函数不尝试通过调用::operator delete()释放存储空间。另见:ISO C条款7.11.2。

并且包括其他更改,其中没有一个声明我们可以在使用new分配的内容上使用free。 因此,草案C99标准的第7.20.3.2free函数仍然是正确的参考,它说:

否则,如果参数与先前由calloc、malloc或realloc函数返回的指针不匹配,或者如果空间已被调用free或realloc释放,则行为未定义


3

正如你所听到的,它们不能混合使用。

需要记住的是,在C++中通常会动态分配大量相对较小的临时对象(例如,很容易编写类似于my_string + ' ' + your_string + '\n'的代码),而在C中,内存分配通常更加谨慎,平均分配大小更大,寿命更长(很可能有人直接为结果分配malloc(strlen(my_string) + strlen(your_string) + 3),没有任何临时缓冲区)。因此,一些C++库将针对大量小型瞬态对象进行优化。例如,它们可能使用malloc()获得三个16k块,然后将每个块用于不超过16、32和64字节的固定大小请求。如果在这种情况下调用delete,它不会释放任何东西 - 它只会将16k缓冲区中的特定条目返回给C++库的空闲列表。如果您调用free(),并且指针恰好指向16k缓冲区中的第一个元素,那么您将意外地释放所有元素;如果指针不是指向第一个元素,则行为未定义(但某些实现,如Visual C++,显然仍会释放给定任何位置的指针所在的块)。

因此,真的不要这样做。

即使在当前系统上表面上可以工作,它也是一颗等待爆炸的炸弹。不同的运行时行为(基于不同的输入、线程竞争条件等)可能会导致后续的故障。使用不同的优化标志、编译器版本、操作系统等进行编译都可能随时破坏它。


1
图书馆应该提供一个释放函数,将其转发到正确的函数。
除了其他人已经说过的(没有兼容性保证),还有可能图书馆链接到与您的程序不同的C库,因此即使函数名称正确,调用free()释放从它们那里接收的指针也会将其传递给错误的释放函数。

0

当内存是由new操作符分配时,您必须使用delete操作符来释放内存。


不,你应该对于new[]使用delete[],而对于new使用delete。 - thang

0

malloc()函数分配内存并将第一个块的地址发送到指定的指针变量,在使用new时,它会分配内存并返回地址。惯例是当您使用malloc()函数时,应该使用delete函数,而在使用new函数分配内存时,使用free()函数更为方便。当使用malloc()函数时,惯例是应该使用相应的realloc()、calloc()、delete()函数,同样地,当您使用new()函数时,应使用相应的free()函数。


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