在 c++ 中,new 是一个关键字(操作符),主要用于在堆内存(heap) 上进行动态内存分配。
与 c 语言中的 malloc 不同,new 不仅分配内存,还会自动调用对象的构造函数来初始化对象。
以下是关于 new 的详细介绍,包括基本用法、原理、高级用法以及现代 c++ 的最佳实践。
1. 基本用法
1.1 分配单个对象
当使用 new 分配单个对象时,它返回指向该类型的指针。
// 1. 分配一个 int,未初始化(值可能是随机的) int* p1 = new int; // 2. 分配一个 int,并初始化为 10 int* p2 = new int(10); // 3. 分配一个类对象,自动调用构造函数 myclass* obj = new myclass(); // 使用完毕后,必须使用 delete 释放 delete p1; delete p2; delete obj;
/*使用new从堆中分配一个int大小内存,不同于malloc,new会返回一个具体类型的指针,而不是void* */
int* fun1()
{
/*这里返回的虽然是一个局部变量指针,但因为是从堆中分配,退出函数后这块内存不会被销毁*/
return new int;
}
/*使用new操作符分配一个int类型内存,并初始化为10 */
int* fun2()
{
/*分配一个int类型内存,赋值为10*/
return new int(10);
}
/*使用new分配一个类对象内存,在分配内存时会调用这个类的构造函数初始化这块内存*/
// my_class* fun3()
// {
// return new my_clash();
// }
/*使用new分配一个数组*/
int* fun4()
{
return new int[10];
}
int main()
{
int *p1 = fun1();
*p1 = 20;
cout << "p1指向的值为:" << *p1 << endl;
delete p1;
int *p2 = fun2();
cout << "p2指向的值为:" << *p2 << endl;
delete p2;
// my_clash *p3 = fun3();
// delete p3;
int *p4 = fun4();
cout << "p4指向的数组为:";
for (int i = 0; i < 10;i++)
{
p4[i] = i;
cout << p4[i] << " ";
}
cout << endl;
system("pause");
return 0;
}

1.2 分配数组
使用 new 也可以分配连续的内存空间(数组)。
// 分配一个包含 10 个整数的数组 int* arr = new int[10]; // 访问数组元素 arr[0] = 5; // 注意:释放数组时必须使用 delete[] (带方括号) delete[] arr;
2.new与malloc的区别 (面试常考)
这是理解 c++ 内存管理的关键点:
| 特性 | new / delete | malloc / free |
|---|---|---|
| 属性 | c++ 关键字 (操作符) | c 语言标准库函数 |
| 初始化 | 分配内存 + 调用构造函数 | 仅分配内存,不初始化 |
| 返回值 | 返回具体类型的指针 (无需强转) | 返回 void* (需要强转) |
| 大小计算 | 自动计算类型大小 | 需要手动计算字节数 (sizeof) |
| 失败处理 | 抛出 std::bad_alloc 异常 | 返回 null |
| 重载 | 允许重载 | 不允许 |
3. 内存分配失败的处理
当堆内存耗尽时,默认情况下 new 会抛出异常,而不是返回空指针。
3.1 标准行为(抛出异常)
try {
int* bigarray = new int[1000000000000]; // 试图分配巨大的内存
} catch (const std::bad_alloc& e) {
std::cout << "内存分配失败: " << e.what() << std::endl;
}
3.2 不抛出异常(std::nothrow)
如果你希望像 c 语言那样在失败时返回 nullptr,可以使用 std::nothrow 版本:
#include <new> // 必须包含
int* p = new(std::nothrow) int[1000000000000];
if (p == nullptr) {
std::cout << "内存分配失败,指针为空" << std::endl;
} else {
delete[] p;
}
4. 进阶:placement new (定位 new)
placement new 允许你在已经分配好的内存上构造对象。这通常用于内存池、嵌入式系统或高性能库中,以避免频繁的内存分配/释放开销。
#include <new> char buffer[sizeof(myclass)]; // 预先分配的栈内存或堆内存 // 在 buffer 的地址上调用 myclass 的构造函数 myclass* p = new (buffer) myclass(123); // 注意:对于 placement new,不能使用 delete p // 必须显式调用析构函数 p->~myclass(); // 如果 buffer 是堆内存,最后释放 buffer // delete[] buffer;
5. 常见陷阱:内存泄漏 (memory leak)
使用 new 最大的风险就是忘记 delete。
void badfunction() {
int* ptr = new int(5);
// ... 做一些操作
// 函数结束,ptr 变量销毁了,但它指向的堆内存没有释放!
// 这就是内存泄漏。
}
此外,配对错误也是常见问题:
new必须配对deletenew[]必须配对delete[]
如果不匹配(例如对数组使用 delete),会导致未定义行为(通常是程序崩溃)。
6. 现代 c++ 最佳实践 (c++11 及以后)
在现代 c++ 开发中,极其不推荐直接使用裸指针(raw pointer)和 new/delete。
应该使用 raii (资源获取即初始化) 原则和 智能指针 来自动管理内存。
6.1std::unique_ptr(独占所有权)
这是最常用的智能指针。当指针超出作用域时,会自动释放内存。
#include <memory> // c++14 推荐写法:使用 make_unique auto ptr = std::make_unique<myclass>(10); // 不需要调用 delete,由 ptr 的析构函数自动处理 ptr->dosomething();
6.2std::shared_ptr(共享所有权)
当多个指针需要指向同一个对象时使用。使用引用计数,当计数归零时自动释放。
#include <memory> auto ptr1 = std::make_shared<myclass>(20); auto ptr2 = ptr1; // 引用计数 +1 // 当 ptr1 和 ptr2 都销毁时,内存才会被释放
总结
new用于在堆上分配内存并初始化对象。- 必须使用
delete释放内存,否则会导致泄漏。 - 数组分配需用
new[]和delete[]。 - 最佳实践:尽量避免直接使用
new,改用std::make_unique或std::make_shared等智能指针,以确保内存安全。
到此这篇关于c++中new操作符的具体使用的文章就介绍到这了,更多相关c++ new操作符 内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论