c++ 智能指针 shared_ptr
创始人
2024-04-12 02:56:55
0

C++ 智能指针 shared_ptr 详解与示例_码农小明的博客-CSDN博客_shared_ptr

一、简介

        shared_ptr 是c++11的智能类,可以在任何地方都不使用的时候自动删除和相关指针,从而彻底消除内存泄漏和指针悬空的问题。

  她遵循共享所有权,即不同的shared_ptr 对象可以与相同的指针想关联

每个shared_ptr对象在内部纸箱两个内存位置:

1、指向对象的指针

2、用于控制引用计数数据的指针

二、shared_ptr 对象的基本操作

1、创建

    std::shared_ptr p1(new int());  // 有两个内存,1是存放int 的地址,2 是用来引用计数的内存地址(在哪里引用了) p1.use_count();  // 这个指针别引用了多长次

 2、创建空的shared_ptr对象

    std::shared_ptr  ptr1 = std::make_shared();

因为带有参数的 shared_ptr 构造函数是 explicit 类型的,所以不能像这样std::shared_ptr p1 = new int();隐式调用它构造函数。创建新的shared_ptr对象的最佳方法是使用std :: make_shared

这里可以说一下explicit  的所用:

explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。

3、分离关联的原始指针

使用reset() 函数,但是这里有两种方式reset()和reset(params);

不带参数的reset()

p1.reset();  // 引用的计数会减一,如果计数为0 ,那么这个指针就会删除

带参数的reset():

p1.reset(new int(34)); // 将内部指向新的指针,因此其作用计算将变成1 

使用nullptr重置:

p1 = nullptr; 
if  1int main()
{//  std::shared_ptr p1(new int());  // 有两个内存,1是存放int 的地址,2 是用来引用计数的内存地址(在哪里引用了) //p1.use_count();  // 这个指针别引用了多长次// 创建一个空对象std::shared_ptr p1 = std::make_shared();std::cout << "p1  空 的引用次数  " << p1.use_count() << std::endl;*p1 = 3334;std::cout << "  p1=  " <<*p1 < p2(p1);std::cout << "  p2的内存地址  " << p2 << std::endl;  //// 下面两个输出都是:2std::cout << "p2 引用次数  = " << p2.use_count() << std::endl;std::cout << "p1 引用次数  = " << p1.use_count() << std::endl;// 比较智能指针,p1 等于 p2  ,由于p1  p2 的地址是一样的,所以p1==p2if (p1 == p2){std::cout << "p1 and p2 are pointing to same pointer\n";}std::cout << "Reset p1 " << std::endl;// 无参数调用reset,无关联指针,引用个数为0p1.reset();std::cout << "p1 Reference Count = " << p1.use_count() << std::endl;// 带参数调用reset,引用个数为1p1.reset(new int(11));std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;// 把对象重置为NULL,引用计数为0p1 = nullptr;std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;if (!p1) {std::cout << "p1 is NULL" << std::endl; // 输出}return  0;}
# endif

 4、自定义删除器 Deleter

delete Pointer;

当 shared_ptr 对象指向数组

// 需要添加自定义删除器的使用方式
std::shared_ptr p3(new int[12]);   // 仅用于演示自定义删除器// 指向数组的智能指针可以使用这种形式
std::shared_ptr p3(new int[12]);  // 正确使用方式

给shared_ptr添加自定义删除器

#if  1   // share_ptr 指针的使用struct A
{A(){std::cout << " A \n";}~A(){std::cout << " ~A \n";}
};void deleter(A* a)
{std::cout << "A   Deleter\n";delete[] a;
}int main()
{std::shared_ptrp4(new A[3], deleter);std::cout << "--------------------------------------------------------\n";//  std::shared_ptr p1(new int());  // 有两个内存,1是存放int 的地址,2 是用来引用计数的内存地址(在哪里引用了) //p1.use_count();  // 这个指针别引用了多长次// 创建一个空对象std::shared_ptr p1 = std::make_shared();std::cout << "p1  空 的引用次数  " << p1.use_count() << std::endl;*p1 = 3334;std::cout << "  p1=  " <<*p1 < p2(p1);std::cout << "  p2的内存地址  " << p2 << std::endl;  //// 下面两个输出都是:2std::cout << "p2 引用次数  = " << p2.use_count() << std::endl;std::cout << "p1 引用次数  = " << p1.use_count() << std::endl;// 比较智能指针,p1 等于 p2  ,由于p1  p2 的地址是一样的,所以p1==p2if (p1 == p2){std::cout << "p1 and p2 are pointing to same pointer\n";}std::cout << "Reset p1 " << std::endl;// 无参数调用reset,无关联指针,引用个数为0p1.reset();std::cout << "p1 Reference Count = " << p1.use_count() << std::endl;// 带参数调用reset,引用个数为1p1.reset(new int(11));std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;// 把对象重置为NULL,引用计数为0p1 = nullptr;std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;if (!p1) {std::cout << "p1 is NULL" << std::endl; // 输出}return  0;}
# endif

 三、shared_ptr 相对于普通指针的优缺点

缺少 ++, – – 和 [] 运算符

与普通指针相比,shared_ptr仅提供-> 、*==运算符,没有+-++--[]等运算符。

NULL检测

当我们创建 shared_ptr 对象而不分配任何值时,它就是空的;普通指针不分配空间的时候相当于一个野指针,指向垃圾空间,且无法判断指向的是否是有用数据。

 

创建 shared_ptr 时注意事项


不要使用同一个原始指针构造 shared_ptr
创建多个 shared_ptr 的正常方法是使用一个已存在的shared_ptr 进行创建,而不是使用同一个原始指针进行创建。
示例:

    int *num = new int(23);std::shared_ptr p1(num);std::shared_ptr p2(p1);  // 正确使用方法std::shared_ptr p3(num); // 不推荐std::cout << "p1 Reference = " << p1.use_count() << std::endl; // 输出 2std::cout << "p2 Reference = " << p2.use_count() << std::endl; // 输出 2std::cout << "p3 Reference = " << p3.use_count() << std::endl; // 输出 1


假如使用原始指针num创建了p1,又同样方法创建了p3,当p1超出作用域时会调用delete释放num内存,此时num成了悬空指针,当p3超出作用域再次delete的时候就可能会出错。

不要用栈中的指针构造 shared_ptr 对象
shared_ptr 默认的构造函数中使用的是delete来删除关联的指针,所以构造的时候也必须使用new出来的堆空间的指针。
示例:

int main()
{int x = 12;std::shared_ptr ptr(&x);return 0;
}


当 shared_ptr 对象超出作用域调用析构函数delete 指针&x时会出错。

建议使用 make_shared


为了避免以上两种情形,建议使用make_shared()<>创建 shared_ptr 对象,而不是使用默认构造函数创建。

std::shared_ptr ptr_1 = make_shared();
std::shared_ptr ptr_2 (ptr_1);


另外不建议使用get()函数获取 shared_ptr 关联的原始指针,因为如果在 shared_ptr 析构之前手动调用了delete函数,同样会导致类似的错误。

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...