new
new 是 C++98/03 中最核心的动态内存分配工具之一。它不仅负责在自由存储区(通常称为堆)申请内存,还会自动调用对象构造函数完成初始化。
和 C 语言的 malloc 相比,new 的最大特点是“类型安全 + 构造语义”:
- 你不需要手动计算字节数。
- 返回值是正确类型指针,不需要强制转换。
- 对类类型会自动执行构造函数。
- 分配失败默认抛出异常,而不是返回空指针。
基本语法
最常见形式:
T* p = new T;
T* p2 = new T(args...);
T* arr = new T[n];
解释:
new T:分配一个T对象,并执行默认构造。new T(args...):分配一个T对象,并执行对应构造函数。new T[n]:分配n个T对象的数组,并逐个构造。
分配内置类型
#include <iostream>
int main() {
int* p = new int(42);
std::cout << *p << '\n';
delete p;
p = 0;
return 0;
}
new int(42) 表示申请一个 int 并初始化为 42。
分配类对象
#include <iostream>
#include <string>
class Person {
public:
Person(const std::string& n, int a) : name(n), age(a) {
std::cout << "Person ctor\n";
}
~Person() {
std::cout << "Person dtor\n";
}
void print() const {
std::cout << name << " (" << age << ")\n";
}
private:
std::string name;
int age;
};
int main() {
Person* p = new Person("Alice", 20);
p->print();
delete p;
p = 0;
return 0;
}
只要使用 new 创建对象,对应释放时就应使用 delete,这样析构函数才能正确执行。
数组分配
#include <iostream>
int main() {
int n = 5;
int* arr = new int[n];
for (int i = 0; i < n; ++i) {
arr[i] = i * 10;
}
for (int i = 0; i < n; ++i) {
std::cout << arr[i] << ' ';
}
std::cout << '\n';
delete[] arr;
arr = 0;
return 0;
}
数组由 new[] 创建,必须由 delete[] 释放,二者必须匹配。
失败处理与异常
默认情况下,分配失败会抛出 std::bad_alloc:
#include <iostream>
#include <new>
int main() {
try {
int* p = new int[1000000000];
delete[] p;
} catch (const std::bad_alloc&) {
std::cout << "memory allocation failed\n";
}
return 0;
}
如果你不希望抛异常,可使用 std::nothrow:
#include <iostream>
#include <new>
int main() {
int* p = new (std::nothrow) int[1000000000];
if (!p) {
std::cout << "allocation failed, p is null\n";
return 0;
}
delete[] p;
return 0;
}
new 与 malloc 的区别
| 对比项 | new | malloc |
|---|---|---|
| 所属 | C++ 运算符 | C 标准库函数 |
| 返回类型 | 目标类型指针 | void* |
| 失败行为 | 抛 std::bad_alloc(默认) | 返回 NULL |
| 初始化 | 可调用构造函数 | 只分配原始字节 |
| 释放方式 | delete / delete[] | free |
最重要原则:
new必须配对delete。new[]必须配对delete[]。- 不要交叉使用
new/free、malloc/delete。
常见错误
- 忘记释放,导致内存泄漏。
- 使用错误释放方式(
new[]却delete)。 - 重复释放同一指针(double delete)。
- 释放后继续解引用悬空指针。
示意:
int* p = new int(10);
delete p;
// *p = 20; // 错误:悬空指针
p = 0;
小结
new 在 C++98/03 中承担了“申请内存 + 构造对象”的双重职责,是面向对象内存管理的核心入口。掌握 new 时,关键不是“怎么申请”,而是“怎么成对释放并保持生命周期清晰”。