new 和 delete 是 C++ 中非常重要的两个关键字,其作用是实现动态对象的管理。正确掌握它们的使用方法对于有效管理程序的内存、提高性能,以及避免内存泄漏等问题至关重要,是编写健壮 C++ 程序的核心技能。
1. 创建/销毁对象
在 C++ 中,new 和 delete 运算符常用于动态对象的创建和销毁。这一节,我们需要了解:
- 单个对象的创建和销毁过程
- 对象数组的创建和销毁过程
#if 1
#include <iostream>
using namespace std;
struct Demo
{
Demo()
{
cout << "Demo 构造函数" << endl;
pArr = new int[100];
}
void do_logic()
{
cout << "Demo Logic 函数" << endl;
}
~Demo()
{
cout << "Demo 析构函数" << endl;
delete pArr;
}
int* pArr;
};
// 1. 单个对象
void test01()
{
Demo* demo = new Demo;
delete demo;
}
// 2. 对象数组
void test02()
{
Demo* demo = new Demo[3];
delete[] demo;
// delete demo;
// free(demo);
int* data = new int[3];
// delete[] data;
// delete data;
// free(data);
// 为什么 demo 使用 delete 或 free 会导致程序崩溃?
// 为什么 data 使用 delete 或 free 不会导致程序崩溃?
}
int main()
{
test02();
return 0;
}
#endif
对象数组的内存结构左图,内置类型数组的内存结构如右图。

2. 分配/释放内存
在 C 语言中,我们使用 malloc 和 free 实现象内存的分配和释放。虽然这两个函数在 C++ 中也适用,但是我们很少直接使用,而是使用 operator new 和 operator delete 函数。接下来,我们通过三个问题,来理解 operator new 和 operator delete 函数的用法和更多细节。
- new/delete 和 operator new/delete 的区别是什么?
- malloc/free 和 operator new/delete 的区别是什么?
- new handler 如何使用?
#if 0
#include <iostream>
using namespace std;
struct Demo
{
Demo()
{
cout << "Demo 构造函数" << endl;
}
~Demo()
{
cout << "Demo 析构函数" << endl;
}
};
// 1. new/delete 和 operator new/delete 的区别是什么?
// 1.1 new/delete 是运算符,用于对象的实例化和销毁
// 1.2 operator new/delete 是函数,用于内存的申请和释放
// 1.2 new/delete 的内存申请通过调用 operator new/delete 实现
void test01()
{
/*
00007FF7499825E1 call operator new (07FF74998104Bh)
00007FF7499825FE call Demo::Demo (07FF7499812DAh)
*/
Demo* demo = new Demo;
/*
00007FF7660423EE call Demo::~Demo (07FF766041082h)
00007FF76604240D call operator delete (07FF7660413EDh)
*/
delete demo;
}
// 2. malloc/free 和 operator new/delete 的区别是什么?
// 2.1 两者都是用于内存申请和释放函数
// 2.2 operator new/delete 是对 malloc/free 函数的封装
// 2.3 内存申请失败时,malloc 返回空指针,operator new 则执行 new handler,或抛出异常
void test02()
{
void* p1 = malloc(100);
free(p1);
void* p2 = operator new(100);
operator delete(p2);
}
void my_new_handler()
{
cout << "my new handler 函数调用" << endl;
}
// 3. new handler 如何使用?
// 3.1 new handler 是内存申请失败时回调的处理函数
// 3.2 使用 set_new_handler 设置回调处理函数 void(*)()
// 3.3 该函数内部一般执行释放资源、日志记录、抛出异常等操作
// 注意:提供 new_handler 之后,可能会陷入无限循环
void test03()
{
// 设置 new handler 函数
set_new_handler(my_new_handler);
void* ptr = operator new(100000000000000000);
}
int main()
{
test03();
return 0;
}
#endif
3. 初始化/清理对象
我们在进行对象创建时,由 new 自动申请内存,并进行对象的初始化。假设,我已有内存,只希望在我持有的内存上初始化对象(即:在指定内存位置调用对象构造函数),这个如何实现?
在 C++ 中,构造函数不能够直接手动调用,但可以通过 placement new 来实现。
有对象初始化就会对应对象清理,由于析构函数是可以直接调用,对于在指定内存位置清理对象,就相对比较简单。
所以,这一节,我们需要学习以下几个问题:
- 如何在指定内存位置构造和清理对象?
- new 和 placement new 的异同是什么?
- placement new 使用时,有什么注意点?
#if 1
#include <iostream>
using namespace std;
struct Demo
{
Demo()
{
cout << "Demo 构造函数" << endl;
}
Demo(int, int)
{
cout << "Demo 有参构造" << endl;
}
void do_logic()
{
cout << "Demo Logic 函数" << endl;
}
~Demo()
{
cout << "Demo 析构函数" << endl;
}
};
// 1. 如何在指定内存位置构造和清理对象?
void test01()
{
// 1. 在堆上
void* ptr = operator new(sizeof(Demo));
Demo* demo = new(ptr) Demo(10, 20);
demo->do_logic();
demo->~Demo();
operator delete(ptr);
// 2. 在栈上
char buf[32] = { 0 };
Demo* d = new(buf) Demo;
d->do_logic();
d->~Demo();
}
// 2. new 和 placement new 的异同是什么?
// 2.1 new 和 placement new 两者都是运算符,placement new 是一个带参数版本的 new
// 2.2 两者都遵循对象的构造函数:operator new + 构造函数
// 2.3 new 分配内存 + 构造函数,placement new 不分配内存 + 构造函数
void test02()
{
char buf[32] = { 0 };
Demo* d = new(buf) Demo;
}
// 3. placement new 使用时,有什么注意点?
// 3.1 确保内存有效性,一定要保证内存大小和位置合法,避免越界操作
// 3.2 内存对齐,确保分配的内存地址满足对象的对齐要求
// 3.3 小心处理内存管理,例如:避免重复构造,可能会导致内存泄漏
struct Sample
{
Sample()
{
cout << "Sample 构造函数" << endl;
int* p = new int[100000];
}
~Sample()
{
if (p != nullptr)
{
delete[] p;
}
cout << "Sample 析构函数" << endl;
}
int* p{ nullptr };
};
void test03()
{
char buf[32] = { 0 };
Sample* sample = nullptr;
for (;;)
{
sample = new (buf) Sample;
}
sample->~Sample();
}
int main()
{
test03();
return 0;
}
#endif



冀公网安备13050302001966号