为什么我们有new/delete,还需要使用malloc/free?

5

在C++中有newdelete,那么mallocfree的用途是什么呢?我猜两者的作用是相同的。

3个回答

8
它们不同。 new 调用构造函数,malloc 只分配内存。
此外,混合使用两者(即使用 newfree 以及使用 mallocdelete)是 未定义行为
在 C++ 中,应该使用 newdeletemallocfree 是为了与 C 兼容而存在的。

好的。但它们都用于内存管理。那么什么时候使用new,什么时候使用malloc呢? - Parag
4
“在C++中,你应该使用new和delete”这句话难道没有回答这个问题吗?不要使用malloc/free。 - user743382
@hvd:那不是正确的建议。你只使用C++中的newdelete的理由并不完全正确(特别是在Nicol回复你的评论后)。 - Alok Save
1
@Als Nicol的回复是不使用new char[]的可能原因,但没有理由不使用我在他回复的评论中提到的::operator new。仍然没有必要使用malloc - user743382

5
在C++中,很少有人会使用mallocfree来代替newdelete。一个可以想到的场景是:如果你不想通过隐式构造函数调用来初始化内存,并且只需要为放置new确保内存分配,那么使用mallocfree而不是newdelete是完全可以的。
另一方面,重要的是要知道mallocnew是不同的!两个重要的区别是:
  • new保证调用类的构造函数来初始化类成员,而malloc则不会。在malloc之后,必须进行额外的memset或相关函数调用来初始化分配的内存以执行有意义的操作。

  • 一个巨大的优势是,在new中,你不需要在每次分配之后检查NULL,只需封装异常处理程序即可完成工作,这样可以节省冗余的错误检查,而malloc则需要。


2
@hvd:new char[] 有一些(非常小的)开销。也就是说,它会在内存块中存储分配的字符数。 - Nicol Bolas
@NicolBolas: free 函数如何知道要释放多少内存?malloc 函数会保存分配的字节数。 - MSalters
@MSalters 或类似的方式可以找到内存中的以下块。一般来说,像new MyClass []这样的语法必须存储确切的计数,以便调用正确数量的解构函数,因为否则无法推导出这些信息。 new char []也可能会这样做(出于正交性的原因 - 它不需要计数); 我所知道的那些没有这样做。 - James Kanze
3
malloc()::operator new()之间的一个重要区别是,你可以合法地替换::operator new()函数,而malloc()保证在其实现中不会使用::operator new()函数,因此你可以在operator new()的重载中使用malloc()函数。(形式上,malloc()free()是唯一拥有这种保证的函数。在我的::operator new()的实现中,我倾向于假设像memsetmemcpy这样的函数也不会调用::operator new()。) - James Kanze
@MSalters 是的。标准实际上保证了new char[N]对于所有可能的类型都正确对齐(因此,new char[N]的返回值的对齐要求大于new int[N]的对齐要求)。然而,从可读性的角度来看,当目标是获取原始内存时,我更喜欢看到使用::operator new(N) - James Kanze
显示剩余4条评论

3
首先,当您提到newdelete时,我假设您指的是表达式,而不是operator newoperator delete函数。 newdelete表达式与mallocfree无关,仅偶尔管理内存;它们的主要作用是管理对象生命周期:一个new表达式将调用operator new函数获取内存,然后调用构造函数;一个delete表达式将在调用operator delete释放内存之前调用析构函数。大多数情况下,应该创建对象,而不仅仅是分配内存,这意味着只使用表达式。
有一些罕见情况需要分离分配和初始化(创建);实现像std::vector这样的东西是一个经典示例,其中你会一次为许多对象分配空间,但一次只构造一个。在这种情况下,您将使用operator new函数进行分配,并使用放置new进行初始化;在另一端,您将显式调用构造函数(类似p->~T())进行销毁,并使用operator delete函数释放内存。
我只能想到两种情况需要在C++中使用mallocfree。第一种是实现自己的替代::operator new::operator delete函数。(我经常用调试版本替换全局::operator new::operator delete,以跟踪分配、在分配的内存周围放置守卫区等)另一种情况是与用C编写的遗留库交互:如果库说要传递由malloc分配的内存的指针(因为它将使用free自行释放),或更常见的是返回由malloc分配的内存的指针,您需要释放,则必须使用mallocfree。(更好的库将提供其自己的分配和释放函数,这些函数几乎与newdelete运算符所做的相同,但总会有像strdup()这样的东西。)

对于那些对答案中提到的第一个用途感兴趣的人,如何编写符合ISO C++标准的自定义new和delete运算符? 是一篇不错的阅读材料。 - Alok Save
@Als 为了100%的一致性,您可以使用语言mallocfree,以及其他任何内容。实际上,有很多函数根本不会分配内存(例如memset);我认为它们也是安全的。实际上,您可能可以放心使用整个C库,但我的调试实现会检查递归,并且如果正在递归调用::operator new,则不会使用超过一个mallocmemsetmemcpy(因此,如果fprintf确实使用::operator new,我就不会遇到无限递归)。 - James Kanze

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