malloc和new的实现有什么区别?堆栈实现方式是什么?

4
在分配内存时,如果内存不可用,new运算符会抛出异常。另一方面,malloc返回NULL。实现差异的原因是什么?此外,在静态内存分配(即在堆栈上)中,如果我们耗尽内存,是否会有异常?
我已经阅读了链接What is the difference between new/delete and malloc/free?,但没有找到关于两者实现差异的答案。
5个回答

5
C代码的问题在于,你应该检查函数的返回值以确保它们正确地工作。但是很多代码并没有检查返回值,结果在最不希望出错的时候爆炸了。
最糟糕的情况是它甚至不会立即崩溃,而是继续损坏内存,在错误的地方数英里之后才崩溃。
因此,在C++中引入了异常。
现在,当有错误发生时,代码不会继续执行(因此不会有内存损坏),而是展开堆栈(可能会强制应用程序退出)。如果您可以处理问题,则必须显式添加代码来处理情况,然后再继续。因此,您不能意外地忘记检查错误条件;您要么检查它,要么应用程序将退出。
new的使用符合这种设计。
如果无法分配内存,则必须显式处理错误。
没有机会忘记检查NULL指针。因此,您不能通过意外使用NULL指针来搞乱内存。
此外,在静态内存分配(例如堆栈)上,如果我们耗尽内存,是否会有例外情况呢?
不幸的是,您不能依赖此功能。
栈溢出时会发生什么是由实现定义的。在许多系统上,甚至无法检测到这种情况,导致内存损坏,最终可能会崩溃。
注意:
如果您#include <new>,则可以使用不抛出异常的new版本,当没有剩余内存时返回NULL。除非有一些专门的需求,否则最好避免使用它。

2

malloc不能抛出异常,因为这会破坏与C的兼容性。new抛出异常是C++中信号错误的首选方式。

据我所知,在早期版本的C++中,new确实在失败时返回0,


实际上,new 有一个无需抛出异常的重载版本,它会返回0而不是抛出异常。 - Matthieu M.

1

我认为一个重要的区别在于:

  • malloc 是 C 语言中分配内存的方式;而在 C 语言中没有例外。
  • new 是 C++ 中面向对象的方式,C++ 中有异常处理机制,使用它们更加规范。


为什么在 C++ 中还要保留 malloc 呢?我想这是因为 C++ 编译器也可以处理 C 代码...

...但我经常听到(几年前在学校时从老师那里听到)在 C++ 中使用 malloc 不被鼓励,应该使用 new


1

冒着可能会增加一些混淆的风险...

  • malloc 是一个常规的 C 函数。因为它是 C,所以它只能通过适合于 C 程序的方式来发出错误信号:使用返回值、通过指针传递的参数或全局变量(如 errno)。
  • new 引入了一个 C++ 表达式,它调用 operator new 来获取内存,然后构造对象。无论是 operator new 还是构造函数都可能抛出异常。

注意:有一个不会抛出异常的 new 表达式版本

大多数 operator new 通常是基于 malloc 实现的,但正如我所指出的,new 表达式不仅仅是获取内存,因为它还构建对象。

它还负责管理直到将其释放给您。也就是说,如果构造函数抛出异常,则它会正确处理已分配的内存,并在 new[] 表达式(构建数组)的情况下调用已经构建的对象的析构函数。

关于堆栈溢出:这取决于您的编译器和操作系统。操作系统可能会标记问题并发出错误信号,编译器可能会进行检查等等...
请注意,gcc引入了分割堆栈选项进行编译,它包括分配最小堆栈,然后按需增加。这样可以很好地避免可能的堆栈溢出问题,但是又引入了另一个二进制兼容性问题,因为与没有使用此选项构建的代码交互可能会变得模糊;我不知道他们计划如何实现这一点。

0
为了完整起见,请记住,您还可以使用 nothrow 模拟旧的(非抛出式)方法--这对于代码中性能关键部分特别适用:
// never throws
char* ptr = new (nothrow) char [1024*1024];

// check pointer for succeeded allocation
if ( !ptr ) { 
  ... // handle error
}

2
在需要性能的关键代码中,也许你不应该分配大量堆内存 :-). 而且至少在C++0x中,new(nothrow)的默认版本要求调用普通的new,捕获异常并返回NULL。[18.6.1.1] - Bo Persson

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