new 与 malloc 的区别 | C & C++

首先区分两个概念:new 和 operator new。new 是一个关键字,和 sizeof 一样,我们无法修改其具体功能。new 主要做三件事:调用 operator new 分配空间、初始化对象、返回指针。本文中这两个概念都有涉及,注意区分。

申请的内存所在位置

new 从自由存储区上为对象动态分配内存空间,而 malloc 函数从堆上动态分配内存。特别的,new 甚至可以不为对象分配内存,使用 placement new 的重载可以做到这一点:

1
2
char* buf = new char[sizeof(T)];
T *p = new(buf) T;

当使用上面这种仅以一个地址调用 new 时,new 调用特殊的 operator new,也就是下面这个版本:

1
void* operator new (size_t, void*);  // 不允许重定义这个版本的 operator new

这个 operator new 不分配任何的内存,它只是简单地返回指针实参。

注:自由存储区是 C++ 基于 new 的一个抽象概念,凡是通过 new 进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配。自由存储区是否能够是堆,这取决于 operator new 的实现细节。自由存储区不仅可以是堆,还可以是静态存储区,这都看 operator new 在哪里为对象分配内存。堆是操作系统维护的一块内存,而自由存储是 C++ 中 通过 new 与 delete 动态分配和释放对象的抽象概念。堆与自由存储区并不等价。几乎所有的 C++ 编译器默认使用堆来实现自由存储。

内存分配失败时的表现

operator new 内存分配失败时,默认会抛出 bac_alloc 异常;malloc 分配内存失败时返回 NULL。

在 new 抛出异常之前,它会先调用一个用户指定的错误处理函数,这就是 new_handler。new_handler 是一个指针类型:

1
2
3
namespace std {
typedef void (*new_handler)();
}

指向了一个没有参数没有返回值的函数,即为错误处理函数。为了指定错误处理函数,用户需要调用 set_new_handler,这是一个声明标准库的函数:

1
2
3
namespace std {
new_handler set_new_handler(new_handler p) throw();
}

函数 set_new_handler 的参数为 new_handler 指针 p,指向了 new 无法分配足够内存时该调用的函数。其返回值也是个指针,指向 set_new_handler 被调用前正在执行(但马上就要被替换)的 new_handler 函数。

更多 new_handler 的细节可以参考《Effective C++》中《条款 49:了解 new-handler 的行为》。

是否调用构造函数/析构函数

new/delete 会调用对象的构造函数/析构函数以完成对象的构造/析构;malloc 则不会。

对数组的处理

new[] 和 delete[] 可以用来创建和销毁数组;malloc 则没有相关的配套设施。

是否可以被重载

operator new 是一个操作符,和 operator=、operator() 一样,可以重载它们,修改分配空间的方式;而 malloc/free 则不允许重载。

能够直观地重新分配内存

使用 malloc 分配的内存后,如果在使用过程中发现内存不足,可以使用 realloc 函数进行内存重新分配实现内存的扩充。realloc 先判断当前的指针所指内存是否有足够的连续空间,如果有,原地扩大可分配的内存地址,并且返回原来的地址指针;如果空间不够,先按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来的内存区域。new 则没有相关的配套设施。

参考

细说new与malloc的10点区别

new 与 malloc 的区别 | C & C++

http://www.zh0ngtian.tech/posts/9aa6f2c.html

作者

zhongtian

发布于

2022-04-30

更新于

2023-12-16

许可协议

评论