虽然语言不会阻止您这样做,但您永远不应该在使用 C++ new 运算符收到的块上使用 C free 函数。 始终对从 new 运算符接收的块使用 C++ delete 运算符,对从 new[] 运算符接收的块使用 delete[] 运算符。
new 运算符为您正在分配的数据类型执行构造函数,而 new[] 运算符为您正在分配的数组的每个元素执行构造函数。 同样,delete 运算符为对象执行析构函数,delete[] 运算符为数组中的每个对象执行析构函数。 free 函数对析构函数一无所知,因此充其量,将 free 与您从 new 或 new[] 运算符收到的块一起使用将默默地无法调用任何析构函数,这可能导致资源泄漏,打开应关闭的文件, 设备处于错误状态等
但是即使你正在使用的对象没有析构函数,也绝对不能保证 new/delete 机制使用与 malloc/calloc/realloc/free 机制相同的堆。 实现不需要为两者使用相同的堆,而且我知道不需要的实现。 但即使它们使用相同的堆,也不能保证关于块大小的信息(或其他一些其他细节)存储在相同的位置或以相同的格式存储两种机制。 因此,如果您在使用 new 运算符或 new[] 运算符分配的块上使用 free 函数,您将面临泄漏该块的风险(因为 free 不知道如何处理它),或破坏 malloc/free heap 和/或 new/delete heap——这会导致下游的各种严重问题。
当然,在 C++ 中,new、new[]、delete 和 delete[] 运算符是可以重载的。 这些运算符的重载版本可能会使用完全不同的、开发人员定义的机制进行分配和释放,这些机制与默认的 malloc/free 堆或默认的 new/delete 堆无关。 潜在地,每种数据类型都可以有自己的 new、new[]、delete 和 delete[] 运算符,其中任何一个都可能与默认的 malloc/free 或 new/delete 机制不兼容。 即使您今天将 free 与来自 new/new[] 的块一起使用,并且它今天“恰好可以工作”,将来对类定义的更改(重载 new/new[]/delete/delete[]), 编译器实现的变化,甚至是编译器选项的变化,都会立即破坏您的代码。 充其量,代码将不可移植。
底线:始终在 new 提供的块上使用 delete,始终在 new[] 提供的块上使用 delete[],始终在 malloc/calloc/realloc 提供的块上使用 free,不要混合使用它们。 如果你把它们混在一起,你只是在自找麻烦。