C 内存操作

malloc

C语言中动态分配内存指令:malloc

void* malloc(size_t size)

malloc将为用户分配size_t字节个内存,并且返回内存分配地址,如果分配失败,则返回0。

如:

1// pa是分配好的内存首地址,4是分配的内存大小
2int* pa = (int*) malloc(4);
3
4// 如果分配失败则pa=0
 1#include<iostream>
 2int main()
 3{
 4	unsigned in;
 5	std::cin >> in;
 6
 7	int* pa = (int*)malloc(in * sizeof(int));
 8	if (pa == nullptr)
 9	{
10		std::cout << "内存分配失败" << std::endl;
11	} 
12	else
13	{
14		pa[0] = 12;
15		pa[1] = 20;
16		pa[2] = pa[0] * pa[1];
17
18		std::cout << pa[0] << " " << pa[1] << " " << pa[2] << std::endl;
19	}
20
21
22	return 0;
23}

calloc

void* calloc(size_t count, size_t size)

为用户分配count * size_t字节个内存,并返回内存分配的首地址,如果分配失败则返回0。

如:

1int* pa = (int*) calloc(1, 4)

其中,pa是分配好的内存首地址,1是要分配的元素个数,4是要分配的每个元素的大小。

如果内存分配失败则返回0。

calloc命令会讲分配好的内存区域设置为0。

realloc

void* realloc(void* _block, size_t size);

为用户重新分配内存,_block是用户已经奉陪好的内存,size是要求重新分配的大小,函数返回重新分配后的内存首地址。

如果分配失败,那么返回0;

如:

1int* pa = (int*)malloc(4);
2     pa = (int*)realloc(pa, 4);
 1#include<iostream>
 2int main()
 3{
 4	unsigned in;
 5	std::cin >> in;
 6
 7	int* pa = (int*)malloc(in * sizeof(int));
 8	int* copy_pa = pa;
 9	if (pa == nullptr)
10	{
11		std::cout << "内存分配失败" << std::endl;
12	}
13	else
14	{
15		pa[0] = 12;
16		pa[1] = 20;
17		pa[2] = pa[0] * pa[1];
18
19		std::cout << pa[0] << " " << pa[1] << " " << pa[2] << std::endl;
20	}
21
22	std::cout << "请输入重新分配内存大小:";
23	std::cin >> in;
24	pa = (int*)realloc(pa, in);
25	std::cout << "realloc之后内存中的值:" << pa[0] << " " << pa[1] << " " << pa[2] << std::endl;
26	std::cout << "未重新分配前的pa地址:"<< copy_pa << "\nrealloc之后pa地址:"<< pa << std::endl;
27	return 0;
28}
29
30/**
31输出:
32100
3312 20 240
34请输入重新分配内存大小:1000
35realloc之后内存中的值:12 20 240
36未重新分配前的pa地址:00E20A50
37realloc之后pa地址:00E21C40
38**/
  • realloc函数会保留内存中已有的值,只是内存地址重新分配了
  • 如果重新分配的内存小于原来的内存,那么首地址不变。
  • 如果重新分配的内存大于原来的内存,那么先判断扩大的内存中是否有已经被分配的,如果没有可以直接重新分配,如果已经有了,那么就需要重新找一段符合需求大小的内存段来重新分配。原内存中的值将会被拷贝过来。

free

void free(void* _block);

_block为需要释放的内存地址;

1int* pa = (int*)malloc(4);
2free(pa);

pa所占用的内存被释放

C++内存操作

分配

数据类型* 指针变量名称 = new 数据类型;

1int* pa = new int;

数据类型* 指针变量名称 = new 数据类型[数量]

1int* pa = new int[5];

分配失败pa返回0;

底层还是使用malloc来实现的。

释放

delete 指针

释放new分配的内存

delete[] 指针

释放new 数据类型[]分配的内存

悬挂指针

内存使用使用完毕之后,使用free或者delete释放之后,原指向该内存区域的指针就称之为悬挂指针,若此时再次使用该指针,可能就会出现问题。

不要使用已被释放的指针

不要重复释放内存

内存碎片

频繁的申请和释放小快内存会造成内存随便,虽然原则上还有内存可以使用,但是实际上由于剩余内存碎片化的存在,使得我们无法分配新的内存,当然,现在也不必担心这样的情况,因为new和delete背后的算法会尽力规避这个风险。

memcpy

void* memcpy(void* _dst, const void* _src, size_t size); memcpy可以将_src区域的内存复制到_dst区域,复制长度为_size

如:

1int a[5]{1001, 1002, 1003, 1004};
2int *p = new int[5];
3memcpy(p, a, 5*sizeof(int));
 1#include<iostream>
 2int main()
 3{
 4	int a[5]{ 1001, 1002, 1003, 1004 };
 5	int* copy_a = new int[5];
 6
 7	memcpy(copy_a, a, 5 * sizeof(int));
 8	for (int i = 0; i < 5; i++) std::cout << copy_a[i] << std::endl;
 9
10	return 0;
11}
12
13/**
14输出:
151001
161002
171003
181004
190
20**/

如果拷贝的空间大于_src的空间,则会将_src后面的的空间也拷贝到_dst,且会将_dst后面的空间覆盖掉。

memset

void* memset(void* _dst, int value, size_t _size)

value的值实际上是0~0xFF。

将指定内存区域的每一个自己的值都设置为val,_size

1int* p = new int[100];
2memset(p, 0, 100 * sizeof(int));
 1#include<iostream>
 2int main()
 3{
 4	int a[5]{ 1001, 1002, 1003, 1004 };
 5	int* copy_a = new int[5];
 6
 7    // 尝试设置四个字节,实际上只接受了最低的两个字节(34)
 8	memset(a, 0x1234, 5 * 4);
 9	memcpy(copy_a, a, 5 * sizeof(int));
10	for (int i = 0; i < 5; i++) std::cout << std::hex << copy_a[i] << std::endl;
11
12	return 0;
13}
14
15/**
16输出:
1734343434
1834343434
1934343434
2034343434
2134343434
22**/

指针的本质是一种特殊的变量类型

声明

1int* a;
2int *a;
3
4// 多个指针变量定义不可以如下定义
5int *a, b;

取址运算

1int a = 200;
2int* pA = &a;

间接运算符

1// 将pA地址里的值设置为400
2*pA = 400;

指针数组

指针也可以通过数组的方式声明

 1#include<iostream>
 2int main() {
 3	int a[5]{ 3,6,8,3,5 };
 4	int* pA[5]{};
 5
 6	for (int i = 0; i < 5; i++)
 7	{
 8		pA[i] = &a[i];
 9		std::cout << "a[" << i << "] 的地址为:" << pA[i] << std::endl;
10	}
11	return 0;
12}
13
14打印内容:
15a[0] 的地址为:001EF864
16a[1] 的地址为:001EF868
17a[2] 的地址为:001EF86C
18a[3] 的地址为:001EF870
19a[4] 的地址为:001EF874

指针大小

使用sizeof()方法来获得指针的大小

1#include<iostream>
2int main() {
3	int		  a{ 111 };
4	int* pA{ &a };
5	std::cout << sizeof(pA) << std::endl;
6}
7
8打印结果:
94

指针类型转换

 1#include<iostream>
 2int main() {
 3	unsigned ua{ 222 };
 4
 5	int* pA = (int*)&ua;
 6	*pA = -1;
 7
 8	std::cout << pA << std::endl;
 9	std::cout << ua << std::endl;
10	return 0;
11}
12
13输出:
14004FF968
154294967295

场景

*ptr++

地址增加。指针加1= 该指针指向地址 + 1 * 改指针类型的大小

 1#include<iostream>
 2int main() 
 3{
 4	int a[]{10001, 20001, 30001, 40001};
 5	int* pA{ &a[0] };
 6
 7	std::cout << "地址为:" << pA << ",值为:" << *pA << std::endl;
 8	std::cout <<*pA++<< std::endl;
 9	std::cout << "地址为:" <<pA << ",值为:" << *pA << std::endl;
10	return 0;
11}
12
13输出:
14地址为:0073FCC8,值为:10001
1510001
16地址为:0073FCCC,值为:20001

(*ptr)++

ptr指针指向地址中的值增加

 1#include<iostream>
 2int main()
 3{
 4	int a[]{ 10001, 20001, 30001, 40001 };
 5	int* pA{ &a[0] };
 6
 7	std::cout << "地址为:" << pA << ",值为:" << *pA << std::endl;
 8	std::cout << (*pA)++ << std::endl;
 9	std::cout << "地址为:" << pA << ",值为:" << *pA << std::endl;
10	return 0;
11}
12
13输出:
14地址为:0077FB40,值为:10001
1510001
16地址为:0077FB40,值为:10002

指针的指针

指针变量也是一个变量,在内容空间中也有具体的地址

 1#include<iostream>
 2int main()
 3{
 4	int a[]{ 10001, 20001, 30001, 40001 };
 5	int* pA{ &a[0] };
 6
 7	int** ppA{&pA};
 8	std::cout << "地址为:" << ppA << ",值为:" << *ppA << std::endl;
 9	std::cout << "地址为:" << *ppA << ",值为:" << **ppA << std::endl;
10	return 0;
11}
12
13输出:
14地址为:00EFF984,值为:00EFF990
15地址为:00EFF990,值为:10001

修改指针的指向

 1#include<iostream>
 2int main()
 3{
 4	int a[]{ 10001, 20001, 30001, 40001 };
 5	int* pA{ &a[0] };
 6
 7	int** ppA{ &pA };
 8	std::cout << "地址为:" << ppA << ",值为:" << *ppA << std::endl;
 9	std::cout << "地址为:" << *ppA << ",值为:" << **ppA << std::endl;
10	std::cout << "地址为:" << pA << ",值为:" << *pA << std::endl;
11
12    // *ppA 即 pA 
13	*ppA = &a[1];
14	std::cout << "地址为:" << ppA << ",值为:" << *ppA << std::endl;
15	std::cout << "地址为:" << *ppA << ",值为:" << **ppA << std::endl;
16	std::cout << "地址为:" << pA << ",值为:" << *pA << std::endl;
17	return 0;
18}
19
20
21输出:
22地址为:005CF82C,值为:005CF838
23地址为:005CF838,值为:10001
24地址为:005CF82C,值为:005CF83C
25地址为:005CF83C,值为:20001

常量指针

定义:

const 变量类型*

所谓常量指针,即这个指针指向的是一个常量的地址,常量指针中,不能对其指向的内存地址进行改变,但是指针指向的这个地址可以改变

 1#include<iostream>
 2int main() 
 3{
 4	const int a{ 100 };
 5	const int b{ 2500 };
 6	int		  c{ 3000 };
 7
 8	const int* ptr{ &a };
 9	ptr = &b;
10
11	// 不能进行如下操作
12	//*ptr = 500;
13
14	ptr = &c;
15	// 虽然c不是常量,但是依然不能进行如下操作,因为ptr是const修饰的
16	//*ptr = 500;
17}

指针常量

定义: 变量类型* const

所谓的指针常量,即这个指针变量是一个常量,一旦初始化就不可以再指向其他内存地址,但是内存地址中的数据可以读写

 1#include<iostream>
 2int main()
 3{
 4	int a{ 100 };
 5	int b{ 2500 };
 6	int c{ 3000 };
 7
 8	int* const ptr{ &a };
 9	// 虽然指针的地址不可以改变,但是指针指向地址中的值可以改变
10	*ptr = 500;
11
12	// 不能进行如下操作
13	// ptr = &b;
14}

指向常量的常量指针

定义:

const 变量类型* const

指向常量的常量指针:即这个指针变量是一个常量,一旦初始化就不可以再指向其他内存地址,因为其本身就是一个指向常量的指针,所以其指向的内存区域也不可以修改。

 1#include<iostream>
 2int main()
 3{
 4	int a{ 100 };
 5	int b{ 2500 };
 6	int c{ 3000 };
 7
 8	const int* const ptr{ &a };
 9	// 不能进行 如下操作
10	// *ptr = 500;
11
12	// 也不能进行如下操作
13	// ptr = &b;
14}

可以通过如下方式修改

 1#include<iostream>
 2int main()
 3{
 4	const int a{ 1000 };
 5	const int b{ 2500 };
 6	const int c{ 3000 };
 7
 8	const int* const ptr{ &a };
 9	// 不能进行 如下操作
10	// *ptr = 500;
11
12	// 也不能进行如下操作
13	// ptr = &b;
14
15	// 去掉a变量的const之后 *ptr 和 *ptrA的值都改变了
16	int* ptrA{ (int*)&a };
17	*ptrA = 9500;
18	std::cout << "地址:" << &a << ",值为:" << a << std::endl;
19	std::cout << "地址:" << ptrA << ",值为:" << *ptrA << std::endl;
20	return 0;
21}

指针和数组

相同

数组的底层实现是利用了指针

从原来上将,指针和数组是同一个方法的不同表达方式,而数组名本身就是一个指针,数组元素只是这个指针按照一定量偏移后对应的内存区域里的内容。

指针同样可以使用[]符号来操作内存

 1#include<iostream>
 2int main() 
 3{
 4	int a[]{ 1000, 2000, 3000 };
 5	int* ptrA{ a };
 6
 7	a[0] = 1001;
 8	a[2] = 3003;
 9
10	// 指针同样可以使用[]符号来操作内存
11	ptrA[1] = 2002;
12	
13	return 0;
14}

对应的汇编代码

 1	;int a[]{ 1000, 2000, 3000 };
 2007F34E2  mov         dword ptr [a],3E8h  
 3007F34E9  mov         dword ptr [ebp-10h],7D0h  
 4007F34F0  mov         dword ptr [ebp-0Ch],0BB8h  
 5	;int* ptrA{ a };
 6007F34F7  lea         eax,[a]  
 7007F34FA  mov         dword ptr [ptrA],eax  
 8
 9	;a[0] = 1001;
10007F34FD  mov         eax,4  
11007F3502  imul        ecx,eax,0  
12007F3505  mov         dword ptr a[ecx],3E9h  
13	;a[2] = 3003;
14007F350D  mov         eax,4  
15007F3512  shl         eax,1		; eax左移1位,等于将eax中的值(4)乘以2
16007F3514  mov         dword ptr a[eax],0BBBh  

不同

在使用`size函数来获取数组大小的时候,返回是整个数组的大小

而指针返回的则是指针类型的大小。

 1#include<iostream>
 2int main() 
 3{
 4	int a[]{ 1000, 2000, 3000 };
 5	int* ptrA{ a };
 6
 7	a[0] = 1001;
 8	a[2] = 3003;
 9
10	// 指针同样可以使用[]符号来操作内存
11	ptrA[1] = 2002;
12	
13	std::cout << "数组a大小" <<sizeof(a) << std::endl;
14	std::cout << "指针ptrA的大小" <<sizeof(ptrA) << std::endl;
15
16	return 0;
17}
18
19输出:
20数组a大小12
21指针ptrA的大小4

多维数组

数组的本质是连续的内存区域,所以所谓的多维数组其实是不存在的,多维只是方便理解而创造出来的逻辑方法。

 1#include<iostream>
 2int main()
 3{
 4	int a[2][5]
 5	{
 6		{1001, 1002, 1003, 1004, 1005},
 7		{2001, 2002, 2003, 2004, 2005}
 8	};
 9
10	int b[2][6]
11	{
12		{0, 1001, 1002, 1003, 1004, 1005},
13		{0, 2001, 2002, 2003, 2004, 2005}
14	};
15
16	int* pA{ a[0] };
17	std::cout << a[1][4] << std::endl;
18	// 因为是连续的内存空间
19	std::cout << pA[9] << std::endl;
20    return 0;
21}

数组指针

注意和指针数组的区别

 1#include<iostream>
 2int main()
 3{
 4	int a[2][5]
 5	{
 6		{1001, 1002, 1003, 1004, 1005},
 7		{2001, 2002, 2003, 2004, 2005}
 8	};
 9
10	int b[2][6]
11	{
12		{0, 1001, 1002, 1003, 1004, 1005},
13		{0, 2001, 2002, 2003, 2004, 2005}
14	};
15
16
17	// 指针数组
18	//int* pArr[5];
19	
20	// 数组指针, 每一行中有5个数据,本质上是一个指针
21	int(*pArr)[5]{a};
22	// 声明了数组指针之后可以按照二维数组的形式获取地址中的数据
23	std::cout << "数组指针:" << pArr[1][4] << std::endl;
24	std::cout << "数组指针大小:" << sizeof(pArr) << std::endl;
25	
26	// 数组指针加1的时候,相当于维度*数据类型的大小,这里是6(维度)*4(int的大小)
27	std::cout << "数组指针大小:" << pArr << std::endl;
28	pArr = pArr + 1;
29	std::cout << "偏移之后数组指针大小:" << pArr << std::endl;
30
31	return 0;
32}
33
34输出:
35数组指针:2005
36数组指针大小:4
37数组指针大小:006FF91C
38偏移之后数组指针大小:006FF930

数组指针加1的时候,相当于维度*数据类型的大小

sizeof()

sizeof()方法在编译期就已经知道了大小。

堆栈

堆的本质是空闲内存,C++中把堆称之为自由存储区,只要是程序加载后没有占用的空闲内存,都是自由存储区域,使用new和malloc申请一块新的内存区域,都是由操作系统从对上操作的。

栈是程序在编译时就确定了大小的一段内存区域,主要是用于里临时变量的存储,栈的效率要高于堆,但是容量有限。


定义

引用是创建一个变量的引用名称

语法: 数据类型& 变量名称{引用对象名称}

如:

1int a{500};
2int& ra{a};

ra = 5200时,相当于a=5200

 1#include<iostream>
 2int main()
 3{
 4	int  a{ 1500 };
 5	int& ref_a{ a };
 6	std::cout << "a=" << a << " ref_a=" << ref_a << std::endl;
 7
 8	ref_a = 2400;
 9	std::cout << "a=" << a << " ref_a=" << ref_a << std::endl;
10	return 0;
11}
12
13输出:
14/**
15a=1500 ref_a=1500
16a=2400 ref_a=2400
17**/

引用一旦赋值就无法改变

 1#include<iostream>
 2int main()
 3{
 4	int  a{ 1500 };
 5	int	 b{ 2000 };
 6	int& ref_a{ a };
 7	std::cout << "a=" << a << " ref_a=" << ref_a << std::endl;
 8
 9	ref_a = 2400;
10	std::cout << "a=" << a << " ref_a=" << ref_a << std::endl;
11	
12	// 这里并不是将ref_a设置成了b的引用,而是将a的值修改成了b
13	ref_a = b;
14
15	return 0;
16}

引用取址

同一个变量的引用指向同一个地址

 1#include<iostream>
 2int main()
 3{
 4	int  a{ 1500 };
 5	int	 b{ 2000 };
 6	int& ref_a{ a };
 7	int& ref_b{ a };
 8	int& ref_c{ a };
 9	int& ref_d{ a };
10	std::cout << "a=" << a << " ref_a=" << ref_a << std::endl;
11
12	ref_a = 2400;
13	std::cout << "a=" << a << " ref_a=" << ref_a << "地址="<< &ref_a <<std::endl;
14	std::cout << "a=" << a << " ref_b=" << ref_b << "地址="<< &ref_b << std::endl;
15	std::cout << "a=" << a << " ref_c=" << ref_c << "地址=" << &ref_c << std::endl;
16	std::cout << "a=" << a << " ref_d=" << ref_d << "地址=" << &ref_d <<std::endl;
17	
18	// 这里并不是将ref_a设置成了b的引用,而是将a的值修改成了b
19	ref_a = b;
20
21	return 0;
22}
23
24输出:
25a=1500 ref_a=1500
26a=2400 ref_a=2400 地址=0107F750
27a=2400 ref_b=2400 地址=0107F750
28a=2400 ref_c=2400 地址=0107F750
29a=2400 ref_d=2400 地址=0107F750

常量引用

引用的值无法修改

const int& a{b}

则无法修改a的值。


定义

std::unique_ptr是所谓智能指针中的一种,主要目的是为了解决原生指针安全性不足的弊端

声明:

std::unique_ptr<类型> 变量名称{};

1// 这里的150表示数组的size为150
2std::unique<int> ptrA{std::make_unique<int>(150)};
3
4// 这里的10表示初始化智能指针所指地址中的值初始化为10
5std::unique<int> ptrA{std::make_unique<int[]>(10)};

常用方法:

reset()

reset()方法会释放掉std::unique_ptr的内存空间,并且将std::unique_ptr设置为nullptr;

 1#include<iostream>
 2int main()
 3{
 4	int* a = new int[5];
 5	// 这里的5表示数组的size为5
 6	std::unique_ptr<int[]> ptr_arr{ std::make_unique<int[]>(5) };
 7	// 这里的5表示初始化智能指针所指地址中的值初始化为5
 8	std::unique_ptr<int> ptr{ std::make_unique<int>(5) };
 9
10	std::cout << "地址为:" << ptr << "值为:" << *ptr << std::endl;
11
12	ptr.reset();
13	std::cout << "地址为:" << ptr << "值为:" << *ptr << std::endl;
14	return 0;
15}

get()

会返回一个std::unique_ptr的指针

用法:

1std::unique_ptr<int> ptrA{std::make_unique<int>(150)};
2int* p = ptrA.get();

get()等于ptrA申请内存时的地址。

release()

会返std::unique_ptr的指针,并将std::unique_ptr设置为nullptr,但是注意release并不会释放器占用的内存空间。

用法:

1std::unique_ptr<int> ptrA{std::make_unique<int>(150)};
2int *ptr = ptrA.release();

此时ptrA所占用的内存空间没有被释放,只是将ptrA的值设置成了nullptr

ptr等于ptrA申请内存时的地址。

std::move

std::unique_ptr指针具有唯一性,因此不能被复制,但是可以转移。

转移语法: 转以后的指针变量 = std::move(转移前的指针变量);

如:

1std::unique_ptr<int> ptrA {std::make_unique<int>(150)};
2std::unique_ptr<int> ptrB {};
3
4ptrB = std::move(ptrA);

转移后ptrA被设置为nullptr

std::shared_ptr

可以有多个std::shared_ptr指向同一个地址,同一个地址下只有当最后一个std::shared_ptr释放的时候,才会释放其所占用的内存空间,std::shared_ptr会记录当前地址有多少个智能指针调用。

语法:

std::shared_ptr<类型> 变量名称

例如:

1std::shared_ptr<int> ptrA{};
2std::shared_ptr<int> ptrB {std::make_shared<int>(5)};

std::make_shared不支持数组

std::shared_ptr<int[]> ptrC{new int[5]{1,2,3,4,5}}

 1#include<iostream>
 2int main()
 3{
 4	int* a{};
 5	std::shared_ptr<int> ptrA{ new int{5} };
 6	std::shared_ptr<int> ptrB{ptrA};
 7
 8	std::cout << ptrA << " " << *ptrA << std::endl;
 9	std::cout << ptrB << " " << *ptrB << std::endl;
10	return 0;
11}
12
13输出:
1400BB6120 5
1500BB6120 5

use_count()

获取一个有多少个指针来调用当前对象:

long std::shared_ptr.use_count();

会返回当前指针共有多少对象调用。

 1#include<iostream>
 2int main()
 3{
 4	int* a{};
 5	std::shared_ptr<int> ptrA{ new int{5} };
 6	std::shared_ptr<int> ptrB{ptrA};
 7	std::shared_ptr<int> ptrC{ptrA};
 8	std::shared_ptr<int> ptrD{ptrA};
 9	std::shared_ptr<int> ptrE{ptrA};
10
11    // 获取当前有多少指针指向ptrA
12	long use_count{ ptrA.use_count() };
13
14	std::cout << ptrA << " " << *ptrA << std::endl;
15	std::cout << ptrB << " " << *ptrB << std::endl;
16	std::cout << use_count << std::endl;
17	return 0;
18}
19
20输出:
2100D89E48 5
2200D89E48 5
235

unique()

将会返回一个bool值,如果当前智能指针是唯一拥有该指针的,那么返回true,否则返回false;

 1#include<iostream>
 2int main()
 3{
 4	int* a{};
 5	std::shared_ptr<int> ptrA{ new int{5} };
 6	// 获取当前有多少指针指向ptrA
 7	int use_count{ ptrA.unique() };
 8	std::cout << use_count << std::endl;
 9
10	std::shared_ptr<int> ptrB{ptrA};
11	std::shared_ptr<int> ptrC{ptrA};
12	std::shared_ptr<int> ptrD{ptrA};
13	std::shared_ptr<int> ptrE{ptrA};
14
15	// 获取当前有多少指针指向ptrA
16	use_count = ptrA.unique();
17
18	std::cout << ptrA << " " << *ptrA << std::endl;
19	std::cout << ptrB << " " << *ptrB << std::endl;
20	std::cout << use_count << std::endl;
21	return 0;
22}
23
24输出:
251
2600EEF6C8 5
2700EEF6C8 5
280

reset()

std::shared_ptr.reset()

reset()会将当前共享指针设置为nullptr,同事如果当前智能指针是最后一个拥有该指针的对象,那么将会释放内存。


— END —