1. 类型安全性和返回类型
new
:是 C++ 的关键字,自动推导类型,返回指定类型的指针。由于new
知道要分配的对象类型,它是类型安全的,且不需要强制类型转换。
int* p = new int(10); // 自动返回 int* 类型,无需强制转换
malloc
:是 C 库函数,需要手动指定分配的字节数,返回void*
类型,因此通常需要显式类型转换,以匹配目标指针类型。它是类型不安全的,因为它只知道分配内存的大小,不知道分配的具体类型。
int* p = (int*)malloc(sizeof(int)); // 需要强制类型转换
2. 内存分配和对象初始化
new
:不仅仅分配内存,它还会调用构造函数来初始化对象。如果是基础类型,如int
、float
,new
允许你直接赋值。
MyClass* obj = new MyClass(); // 分配内存并调用构造函数
int* p = new int(10); // 分配内存并将 10 赋值给该地址
malloc
:只负责分配原始内存,不会调用构造函数,也不会进行初始化。对于对象类型,如果你需要初始化对象,必须手动调用构造函数。
MyClass* obj = (MyClass*)malloc(sizeof(MyClass)); // 仅分配内存,不调用构造函数
3. 内存释放和对象销毁
new
:与new
相对应的释放内存操作是delete
。delete
不仅释放内存,还会调用析构函数,从而保证对象的资源正确释放(如关闭文件、释放动态分配的内存等)。
delete p; // 释放单个对象,调用析构函数
delete[] p; // 释放数组对象,调用每个元素的析构函数
malloc
:与malloc
相对应的释放内存操作是free()
。free()
只会释放内存,不会调用析构函数。如果对象持有资源(如动态内存或文件句柄),这些资源将不会被正确释放,可能导致内存泄漏或资源泄漏。
free(p); // 仅释放内存,不调用析构函数
4. 分配数组
new[]
:可以用于动态分配对象数组。它分配内存并为数组中的每个对象调用构造函数。当使用delete[]
释放数组时,每个对象的析构函数都会被调用。
int* arr = new int[10]; // 分配一个包含 10 个 int 的数组
delete[] arr; // 使用 delete[] 来释放数组
malloc
:用于分配任意大小的内存块,包括数组,但它并不知道内存块的元素类型,也不会调用构造函数和析构函数。手动管理数组的初始化和释放非常复杂。
int* arr = (int*)malloc(10 * sizeof(int)); // 分配 10 个 int 大小的内存
free(arr); // 释放内存,不调用析构函数
5. 异常处理
new
:如果内存分配失败,new
会抛出std::bad_alloc
异常,这使得处理内存分配失败更加方便。
try {
int* p = new int[1000000000]; // 分配大量内存
} catch (std::bad_alloc& e) {
std::cerr << "Memory allocation failed: " << e.what() << std::endl;
}
malloc
:如果内存分配失败,malloc
返回NULL
,你必须手动检查返回值来处理错误。这种方法不如new
的异常处理机制方便。
int* p = (int*)malloc(1000000000 * sizeof(int));
if (!p) {
std::cerr << "Memory allocation failed" << std::endl;
}
6. 可重载性
new
:可以在类中重载new
和delete
操作符,以控制特定类的内存分配方式。
class MyClass {
public:
void* operator new(size_t size) {
std::cout << "Custom new operator" << std::endl;
return ::operator new(size); // 调用全局 new
}
void operator delete(void* ptr) {
std::cout << "Custom delete operator" << std::endl;
::operator delete(ptr); // 调用全局 delete
}
};
malloc
:是标准库函数,无法被重载。
7. 语言特性
new
是 C++ 的语言级别操作符,支持对象的构造与析构。malloc
是 C 语言中的标准库函数,只能分配内存,不支持类的构造与析构。
总结:
特性 |
|
|
返回类型 | 返回类型安全的指针 | 返回 |
初始化 | 调用构造函数并初始化 | 仅分配内存,不初始化 |
释放内存 |
|
|
异常处理 | 内存不足时抛出 | 内存不足时返回 |
数组分配 | 支持 | 分配内存块,不关心类型 |
可重载性 | 可以在类中重载 | 无法重载 |
在 C++ 中,new
更适合分配和管理对象,因为它支持构造函数和析构函数的自动调用。而 malloc
更适用于与 C 代码的兼容性场景中,只负责内存分配,不关心对象的初始化和销毁。