十三、指针和引用(三)

1、std::unique_ptr(唯一智能指针)

1)概念

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

//std::unique_ptr指针的声明语法
std::unqiue_ptr<类型>变量名称{};

//示例
std::unique_ptr<int>ptrA{std::make_unique<int>(150)}; // 申请一个具有1个int类型大小的指针,值为150
std::cout<<*ptrA;  //指针使用

std::unique_ptr<int[]>ptrB{new int[5]}; //C++14之前的写法,申请一个具有5个int类型大小的指针
std::unique_ptr<int[]>ptrB{std::make_unique<int[]>(10)};   //申请一个具有5个int类型大小的指针
ptrB[0]=250;  //指针使用,此声明方法,只能通过数组访问

2)唯一智能指针特性

std::unique_ptr的特点是该指针具有唯一性,因此无法让两个std::unique_ptr指针存放相同的内存地址,如下:

std::unique_ptr<int>ptrA{std::make_unique<int>(150)};
std::unique_ptr<int>ptrB{};
//ptrA=ptrB;      //错误,无法直接赋值

#include <iostream>

int main()
{
	int* a = new int[5];
	std::unique_ptr<int[]>intptr{ std::make_unique<int[]>(5) };     //申请一个具有5个int类型大小的指针

	std::unique_ptr<int>intptrA{ std::make_unique<int>(5) };  // 申请一个具有1个int类型大小的指针,值为5

	std::cout << intptr << " " << intptr[0]<<std::endl;        //013D5C98 0
	std::cout << intptrA << " " << *intptrA << std::endl;      //013DEC10 5
}

3)reset()用法

​ reset将会释放std::unique_ptr的内存空间,并且将std::unique_ptr设置为nullptr;

//reset()用法示例
std::unique_ptr<int>ptrA{std::make_unique<int>(150)};
ptrA.reset();  //此时ptrA的内存空间被释放,ptrA的值设置成了nullptr
//reset()示例
#include <iostream>

int main()
{
	int* a = new int[5];
	delete[] a;        //释放new申请的内存空间

	std::unique_ptr<int>ptrA{ std::make_unique<int>(100) };
	std::cout << "释放内存前的地址:"<<ptrA << std::endl;
	ptrA.reset();           //释放唯一智能指针
	std::cout << "释放内存后的地址:" << ptrA << std::endl;
}

4)get()用法:返回一个std::unique_ptr的指针

//get()用法
std::unique_ptr<int>ptrA{std::make_unique<int>(150)};
int*p = ptrA.get();     //相当于将ptrA申请时的内存赋值给p

5)release()用法

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

//relseae()用法
std::unique_ptr<int>ptrA{std::make_unique<int>(150)};
int* p = ptrA.release(); 
//此时ptrA占用的内存空间没有被释放,ptrA的值设置成了nullptr,p等于ptrA申请内存时的地址
//release只是将申请的内存地址设置为了0,并没有释放,并且将原理的地址进行了返回
#include <iostream>

int main()
{

	int* a = new int[5];
	std::unique_ptr<int>ptrA{ std::make_unique<int>(100) };
	std::cout << "release前的地址:" << ptrA << std::endl;
	a = ptrA.release();
	std::cout << "release后的地址:" << ptrA << std::endl;
	std::cout << "a的地址:" << a << std::endl;
}

6)唯一智能指针的转移(move)

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

//唯一智能指针转移语法
转移后的指针变量=std::move(转移前的指针变量);

//示例
std::unique_ptr<int>ptrA{std::make_unique<int>(150)};
std::unique_ptr<int>ptrB;
ptrB=std::move(ptrA);  //将ptrA的地址转移到ptrB,转移后ptrA被设置为nullptr

2、std::shared_per(共享智能指针)

1)共享智能指针语法

//共享智能指针语法
std::shared_ptr<类型>变量名称{};

//示例
std::shared_ptr<int>ptrA{};
std::shared_ptr<int>ptrB{std::make_shared<int>(5)};

//注:std::make_shared不支持新式的数组的定义方式,只能通过new的方式
std::shared_ptr<int[]>ptr{new int[5]{1,2,3,4,5}};
//共享智能指针的定义及使用
#include <iostream>

int main()
{
	int* a{};
	std::shared_ptr<int>ptrA{ std::make_shared<int>(5) };
	std::shared_ptr<int>ptrB{ ptrA };       //共享ptrA的内存地址
	std::shared_ptr<int>ptrC{ ptrA };

	std::cout << "ptrA的内存地址为:" << ptrA << std::endl;
	std::cout << "ptrB的内存地址为:" << ptrB << std::endl;
	std::cout << "ptrA的内存地址为:" << ptrC << std::endl;
	std::cout << "\n";
	std::cout << "ptrA的值为:" << *ptrA << std::endl;
	std::cout << "ptrB的值为:" << *ptrB << std::endl;
	
}

2)共享智能指针特性

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

3)统计共享指针当前有多少个对象调用(use_count)

//统计共享指针当前有多少个对象调用
long std::shared_ptr.use_count();  

.user_count();  //会返回当前指针共有多少个对象调用
//use.count()用法示例
#include <iostream>

int main()
{
	int* a{};
	std::shared_ptr<int>ptrA{ std::make_shared<int>(5) };
	std::shared_ptr<int>ptrB{ ptrA };       //共享ptrA的内存地址
	std::shared_ptr<int>ptrC{ ptrA };

	std::cout << "ptrA指针共有多少个指针调用:" << ptrA.use_count() << std::endl;

}

5)判断共享智能指针是否唯一(unique)

//判断共享智能指针是否唯一
bool std::shared_ptr.unique();
//unique()返回一个bool值,如果当前智能指针是唯一拥有该指针的,那么返回true,负责返回false
注:C++17标准无法使用该函数,只能在17之前使用
//unique()用法
#include <iostream>

int main()
{
	int* a{};
	std::shared_ptr<int>ptrA{ std::make_shared<int>(5) };
	std::cout << "判断指针指针ptrA是否唯一:" << ptrA.unique() << std::endl;
	std::shared_ptr<int>ptrB{ ptrA };       //共享ptrA的内存地址
	std::shared_ptr<int>ptrC{ ptrA };
	std::cout << "判断指针指针ptrA是否唯一:" << ptrA.unique() << std::endl;
}

4)共享智能指针的释放

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

//共享智能指针的释放
std::shared_ptr.reset();
//reset()使用
#include <iostream>

int main()
{
	int* a{};
	std::shared_ptr<int>ptrA{ std::make_shared<int>(5) };
	std::shared_ptr<int>ptrB{ ptrA };       //共享ptrA的内存地址
	std::shared_ptr<int>ptrC{ ptrA };

	ptrB.reset();                   //只是修改指针的指向,并不释放指针内存地址
	std::cout << ptrB << std::endl;
	ptrA.reset();
	std::cout << ptrA << std::endl;
	std::cout << ptrC << std::endl;
	ptrC.reset();                  //释放智能指针的内存地址
	std::cout << ptrC << std::endl;
}