代码仓库shanchuann/CPP-Learninng

可执行程序(进程)的虚拟地址空间:

image-20251016142349350

在C++中,newdelete是用于动态内存管理的核心运算符,它们不仅负责内存的分配与释放,还会自动调用对象的构造函数和析构函数,是面向对象编程中管理动态对象的关键工具。

在C语言中,从堆区申请空间的库函数有malloc realloc calloc 三个,无论用谁申请,最终要使用free释放

在C++中,使用new申请,使用delete释放

new的基本用法

new的作用是动态分配内存并构造对象,根据分配的对象类型可分为以下几种形式:

单个对象的动态分配

语法:类型* 指针 = new 类型(初始化值);

  • 分配一块能容纳该类型对象的内存;
  • 自动调用该类型的构造函数(如果是类对象);
  • 返回指向该对象的指针(类型匹配,无需强制转换)。
1
int* New = new int(12); //1. sizeof(int) 2. malloc(sizeof(int)) 3. put 12 in that memory 4. return address of that memory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;

class A {
public:
A(int x) : num(x) { // 构造函数
cout << "A的构造函数被调用,num=" << num << endl;
}
~A() { // 析构函数
cout << "A的析构函数被调用,num=" << num << endl;
}
private:
int num;
};

int main() {
// 基本类型(无构造函数,仅分配内存并初始化)
int* p = new int(10); // 分配int内存,初始化为10
cout << *p << endl; // 输出:10

// 类对象(会调用构造函数)
A* a = new A(20); // 分配A对象内存,调用A(20)构造函数

return 0;
}

数组的动态分配

语法:类型* 指针 = new 类型[数组大小];

  • 分配一块能容纳N个该类型对象的连续内存;
  • 对类对象数组,会为每个元素调用默认构造函数(无参构造);
  • 返回指向数组首元素的指针。
1
2
3
4
5
6
// 数组分配(基本类型)
int* arr = new int[5]; // 分配5个int的连续内存,未初始化
int* arr2 = new int[3]{1, 2, 3}; // C++11起支持初始化

// 类对象数组(需有默认构造函数)
A* arrA = new A[2]; // 调用2次A的默认构造函数(需先定义A的无参构造)

关键字和函数的使用方式

1
2
3
4
5
6
7
8
int main() {
int* p = new int{ 10 }; // new int(10) -> single integer
delete p; // delete is used to deallocate memory allocated by new

p = (int*)::operator new(sizeof(int)); // ::operator new(sizeof(int)) -> single integer
::operator delete(p); // ::operator delete is used to deallocate memory allocated by ::operator new
return 0;
}

new关键字的核心功能是:分配内存 + 构造对象(对基本类型则是 “分配内存 + 初始化”)

delete关键字的核心功能是:析构对象 + 释放内存(对基本类型则是 “直接释放内存”)。必须与new的形式严格匹配

operator newoperator delete是 C++ 中的全局函数(可重载),它们的作用是仅负责内存的分配与释放,不涉及对象的构造 / 析构(类似 C 语言的malloc/free)。new/delete关键字的底层会调用这些函数。

operator new函数的使用方式

operator new的核心功能是:分配原始内存块(按指定字节数),返回void*指针(需手动强转),不进行任何初始化或构造。语法:void* operator new(size_t 字节数);(全局版本,可加::指定全局作用域)

1
2
3
4
// 分配能容纳1个int的内存(4字节,假设int占4字节)
void* raw_mem = ::operator new(sizeof(int)); // 全局函数,仅分配内存
int* p = (int*)raw_mem; // 强转为int*(必须手动转换)
*p = 10; // 手动初始化(operator new不做初始化)
  • 数组版本:operator new[],用于分配数组内存(本质与operator new类似,多处理一些数组元数据):

    1
    2
    void* arr_mem = ::operator new[](3 * sizeof(int));  // 分配3个int的内存
    int* arr = (int*)arr_mem;
  • 不抛异常版本:operator new(size_t, nothrow_t),失败返回nullptr

    1
    void* mem = ::operator new(sizeof(int), nothrow);  // 失败返回nullptr

operator delete函数的使用方式

operator delete的核心功能是:释放由operator new分配的原始内存,不涉及析构函数调用。语法:void operator delete(void* 指针);(全局版本,需与operator new匹配)

1
::operator delete(p);  // 释放由::operator new分配的int内存(仅释放,不处理析构)
  • 数组版本:operator delete[],与operator new[]匹配:

    1
    ::operator delete[](arr);  // 释放数组内存

定位new(placement new)

特殊用法:在已分配的内存上构造对象(不重新分配内存),语法:
类型* 指针 = new (已有内存地址) 类型(构造参数);

场景:常用于内存池(重复利用已分配的内存块,提高效率)。

1
2
3
4
5
6
7
8
int main() {
// buffer on stack
char Newbuff[128];

// placement new
new(Newbuff) int(10);
new(Newbuff + sizeof(int)) int(20);
}

image-20251016150739201

delete的基本用法

delete的作用是销毁对象并释放内存,必须与new匹配使用,否则会导致未定义行为(如内存泄漏、程序崩溃)。

释放单个对象

语法:delete 指针;

  • 先调用对象的析构函数(类对象);
  • 再释放指针指向的内存。
1
2
3
4
5
int* p = new int(10);
delete p; // 释放int内存(基本类型无析构,直接释放)

A* a = new A(20);
delete a; // 先调用A的析构函数,再释放内存

释放数组

语法:delete[] 指针;

  • 对类对象数组,先为每个元素调用析构函数;
  • 再释放整个数组的内存。

注意new[]必须对应delete[],否则会导致类对象析构函数调用不完整(内存泄漏)。 =

1
2
3
4
5
int* arr = new int[5];
delete[] arr; // 释放数组内存(基本类型无析构,直接释放)

A* arrA = new A[2];
delete[] arrA; // 先调用2次A的析构函数,再释放数组内存

newmalloc的区别

特性 new(C++运算符) malloc(C库函数)
操作 可初始化 不可初始化
功能 分配内存 + 调用构造函数(类对象) 仅分配内存(按字节数)
返回类型 对应类型指针(无需强制转换) void*(需手动强制转换)
分配失败 默认抛出std::bad_alloc异常(可改用nothrow 返回NULL
大小计算 自动根据类型计算(如new int无需指定4字节) 需手动指定字节数(如malloc(4)
重载 可重载operator new自定义分配逻辑 不可重载

deletefree的区别

特性 delete(C++运算符) free(C库函数)
功能 调用析构函数(类对象) + 释放内存 仅释放内存(不调用析构函数)
适用场景 必须与new/new[]匹配 必须与malloc/calloc/realloc匹配
指针合法性 释放空指针(NULL)是安全的 释放空指针(NULL)是安全的

对于内置类型,new/delete/malloc/free可以混用

new分配失败的处理

  • 默认行为:new分配内存失败时,会抛出std::bad_alloc异常(需包含<new>头文件)。
  • 不抛异常版本:使用nothrow参数,失败时返回NULL(需手动检查)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <new>  // 包含bad_alloc和nothrow

// 默认:抛异常
try {
int* p = new int[1000000000]; // 若内存不足,抛出bad_alloc
} catch (const bad_alloc& e) {
cout << "分配失败:" << e.what() << endl;
}

// nothrow版本:返回NULL
int* q = new (nothrow) int[1000000000];
if (q == NULL) {
cout << "分配失败" << endl;
}

newdelete是C++动态内存管理的基础,核心是“分配+构造”与“析构+释放”的配对。实际开发中,应优先使用智能指针减少手动管理的风险。