C++动态内存申请允许程序在运行时根据实际需求分配内存,相比编译时确定的静态内存,动态内存的灵活性更高,适合处理大小不确定的数据场景。常用的动态内存申请方式主要有new和malloc两种,两者虽然都能实现内存分配,但在底层逻辑和使用特性上存在明显差异。

C++动态内存申请的基本方式
C++中动态内存申请的两种核心方式分别是new运算符和malloc函数,两者都从堆区分配内存,但使用语法和底层实现不同。
使用new申请动态内存
new是C++内置的运算符,使用语法简洁,不需要手动计算内存大小,会根据类型自动分配对应字节数的内存。申请单个对象时使用new 类型,申请数组时使用new 类型[数量],释放内存时对应使用delete和delete[]。
以下是new申请单个int和int数组的示例:
#include <iostream>
using namespace std;
int main() {
// 申请单个int类型内存,初始化为10
int* p1 = new int(10);
cout << *p1 << endl; // 输出10
delete p1; // 释放单个对象内存
p1 = nullptr;
// 申请包含5个int的数组内存
int* arr = new int[5];
for (int i = 0; i < 5; i++) {
arr[i] = i * 2;
}
delete[] arr; // 释放数组内存
arr = nullptr;
return 0;
}
使用malloc申请动态内存
malloc是C语言标准库中的函数,需要包含<stdlib.h>头文件,使用时需要手动传入需要分配的字节数,返回的是void*类型的指针,需要手动强转为对应类型的指针。释放内存时使用free函数。
以下是malloc申请int和int数组的示例:
#include <iostream>
#include <stdlib.h>
using namespace std;
int main() {
// 申请单个int类型内存,malloc返回void*需要强转
int* p2 = (int*)malloc(sizeof(int));
*p2 = 20;
cout << *p2 << endl; // 输出20
free(p2); // 释放内存
p2 = nullptr;
// 申请包含5个int的数组内存
int* arr2 = (int*)malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) {
arr2[i] = i * 3;
}
free(arr2); // 释放数组内存
arr2 = nullptr;
return 0;
}
new和malloc的核心区别
两者虽然都能完成动态内存分配,但在多个维度存在明显差异,具体对比如下:
| 对比维度 | new | malloc |
|---|---|---|
| 属性 | C++内置运算符 | C标准库函数 |
| 内存大小计算 | 自动根据类型计算所需字节数 | 需要手动传入分配的字节数 |
| 返回值 | 返回对应类型的指针,不需要强转 | 返回void*类型,需要手动强转为目标类型 |
| 构造析构调用 | 申请对象内存时会调用构造函数,释放时调用析构函数 | 只会分配内存,不会调用构造和析构函数 |
| 内存分配失败处理 | 默认抛出std::bad_alloc异常 | 返回NULL指针 |
| 重载支持 | 支持运算符重载,可自定义内存分配逻辑 | 不支持重载 |
构造析构调用的差异示例
对于自定义类型,new和malloc的差异会非常明显,以下代码可以直观展示两者的区别:
#include <iostream>
#include <stdlib.h>
using namespace std;
class Test {
public:
Test() {
cout << "Test构造函数被调用" << endl;
}
~Test() {
cout << "Test析构函数被调用" << endl;
}
};
int main() {
cout << "使用new申请对象内存:" << endl;
Test* t1 = new Test(); // 会调用构造函数
delete t1; // 会调用析构函数
cout << "使用malloc申请对象内存:" << endl;
Test* t2 = (Test*)malloc(sizeof(Test)); // 不会调用构造函数
free(t2); // 不会调用析构函数
return 0;
}
上述代码运行后,new申请的对象会输出构造和析构的提示,而malloc申请的对象不会有相关输出,这也说明malloc只做了内存分配,没有完成对象的初始化和销毁逻辑。
内存分配失败的处理差异
当堆区内存不足时,new和malloc的处理方式不同,使用时需要注意:
#include <iostream>
#include <stdlib.h>
#include <new>
using namespace std;
int main() {
// malloc分配失败返回NULL
int* p_malloc = (int*)malloc(1024 * 1024 * 1024 * 10); // 尝试分配10G内存,大概率失败
if (p_malloc == NULL) {
cout << "malloc分配内存失败" << endl;
}
// new默认分配失败抛出异常,也可以设置为不抛异常返回NULL
try {
int* p_new = new int[1024 * 1024 * 1024 * 10];
} catch (bad_alloc& e) {
cout << "new分配内存失败,异常信息:" << e.what() << endl;
}
// new也可以设置为不抛异常,返回NULL
int* p_new_nothrow = new (nothrow) int[1024 * 1024 * 1024 * 10];
if (p_new_nothrow == nullptr) {
cout << "new(nothrow)分配内存失败" << endl;
}
return 0;
}
使用建议
在C++开发中,如果是处理内置类型,new和malloc都可以使用,但new的语法更简洁,不需要手动计算字节数和强转指针,优先选择new。如果是处理自定义类型,必须使用new,否则无法调用构造函数完成对象初始化,释放时也需要对应使用delete,避免内存泄漏和未定义行为。另外需要注意,new对应delete,new[]对应delete[],malloc对应free,不能混用,否则可能导致程序崩溃。