ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

智能指针 shared_ptr

2020-06-07 13:07:47  阅读:199  来源: 互联网

标签:初始化 智能 new shared ptr 指针


一、语法:

shared_ptr p(new int(100)); // 正确!显示构造,直接初始化
shared_ptr p = new int(100); // 错误!智能指针是explicit,不可用隐式类型转换,必须直接用初始化

二、简介:

//常见的几种智能指针 shared_ptr, unique_ptr, weak_ptr,都是类模板,需要用<> 指定指向的类型
shared_ptr // 共享式指针,多个指针指向同一个对象时,最后一个指针销毁时,这个对象会被销毁, 有额外开销
weak_ptr   //辅助shared_ptr 工作
unique_ptr //独占式指针,同一个时间内,只有一个指针指向该对象,该对象的所有权可以移交出去

三、引用计数
1、工作原理:引用计数,当有新的shared_ptr 指向该对象时,引用计数+1,当shared_ptr 指针被析构的时候,引用计数-1

2、引用计数增加的情况:
(1)shared_ptr 创建

shared_ptr p1(new int(100));
shared_ptr p2 = std::make_shared(100); // 可以用 make_shared 来初始化智能指针
shared_ptr p3(p1);    // 注意,裸指针智能初始化一个智能指针,不能用于初始化多个智能指针,一般用智能指针去初始化其他智能指针

(2)作为实参往函数中传递,传值会增加,传引用不会

(3)作为函数的返回值

3、引用计数减少的情况:

(1)shared_ptr  //析构的时候(局部的shared_ptr 离开其作用域)
(2)shared_ptr  //指向其他对象
(3)p = nullptr; // 将智能指针置空,同时引用计数-1,若引用计数为0,则释放其指向的内存
// 当一个shared_ptr 引用计数从1变成0,它会自动释放自己所管理的内存

四、shared_ptr 的常用操作

shared_ptr p1;
(1)use_count(); // 返回多少个智能指针指向某个对象
int i = p1.use_count();
(2)unique();   // 如果只有一个智能指针指向某个对象返回true, 否则false
p1.unique();
(3)reset(); //
(3.1)pi.reset();   // 将pi 置空,如果原来pi 计数为1,释放该内存,如果计数不为1,则引用计数-1,《没有释放》其指向的内存
(3.2)pi.reset(new int(1)); // 将pi 指向新的内存,如果原来pi 计数为1,释放该内存,如果计数不为1,则引用计数-1,《没有释放》其指向的内存
(4) * 解引用,与普通指针相同
(5)get(); // 返回裸指针
小心使用,shared_ptr可能会释放裸指针所指向的内存

五、自定义删除器
1) 我们可以自定义删除器,取代系统提供的默认删除器(系统默认应该只是delete该指针)
2) 当智能指针需要删除所指向的对象时,编译器会调用我们自己指定的删除器
3) 删除器是和一块内存对应的,初始化之后,内存的释放智能用指定的删除器,没有指定就是用默认的
4) std::make_shared 不能指定删除器,所以智能用new这种方式来初始化的时候指定删除器
例子:
(1)删除器可以是函数

void MyDelete(int* p)
{
    // 自定义操作
    delete p; // 因为取代了系统默认的删除器,所以需要自己手动释放
}
shared_ptr p1(new int(100), MyDelete); // 删除器在指针初始化的时候,作为删除传给该指针

(2)删除器也可以是lambda 表达式

shared_ptr p1(new int(100), [](int* p) {
// 自定义操作
delete p;
});
// 注意:系统默认的删除器,只是删除裸指针,即delete p ,当智能指针指向的是动态分配的数组时,默认的删除器还是delete p, 而不是delete []p。

(3)能够正常释放动态分配数组的情况
(3.1)

shared_ptr p1(new T[10], [](int* p) {
    // 自定义操作
    delete []p;
});

(3.2)std::default_delete 模板类

shared_ptr p1(new T[10], std::default_delete<T[]>());

(3.3)C++17 的新写法

shared_ptr<T[]> p1(new T[10]);

六、一些错误使用情况

1、用裸指针构造临时的智能指针形参

// 假设函数 void myfun(shared_ptr sp);
// 错误示范:
int* p = new int(10);
myfun(shared_ptr(p)); //用p构造临时的智能指针形参,
//在出了这个函数之后指针指针所指的内存会被释放掉,则原来裸指针p 所指的内存会被释放掉,会出现空指针
// 正确使用:
shared_ptr ps(p);
myfun(ps);
// 小结:将一个裸指针绑定到一个shared_ptr上, 内存的管理的任务就交给了shared_ptr, 之后就不应该在使用裸指针来访问该段内存
// 如果之后仍想使用裸指针,则在赋值shared_ptr 时,应该用裸指针的Clone();

2、不能用裸指去初始化多个智能指针

// 不能用一个裸指针去初始化多个智能指针,也不能用裸指针去赋值多个智能指针,最好都是用智能指针去初始化,或者赋值智能指针。
// 错误示例:
int* p = new int(10);
shared_ptr p1(p);
shared_ptr p2(p); // 正确写法: shared_ptr p2(p1); // 用智能指针去初始化另一个智能指针
// 初始化形成的两个智能指针的引用计数都是1,说明这两个智能指针无关联
// 这样的话,程序结束的时候p 指向的内存会被释放两次,导致程序错误。

3、.get()函数的使用

(1)不能delete .get()返回的裸指针
(2)不能用.get()返回的裸指针去初始化其他智能指针,原因同上一点的注意事项

4、不要把类对象指针(this)作为shared_ptr 返回,改用enable_shared_from_this

// 用法:
class T :public enable_shared_from_this // enable_shared_from_this 标准库类模板
{
    public:
    void GetSelf(){
    return shared_from_this();
    // 如果直接返回shared_ptr(this); 则使用裸指针去初始化指针指针,会导致(1)中的问题
  }
}
// 调用:
shared_ptr pt1(new T);
shared_ptr pt2 = pt1->GetSelf();
// 原理:enable_shared_from_this 中有一个弱指针(weak_ptr)监视this,在调用shared_from_this()方法时,
// 内部会调用weak_ptr 的lock()方法,会让shared_ptr 引用计数+1,同时返回这个shared_ptr。
// 小结:不能用裸指针去初始化两个或两个以上的智能指针,超过一个的指针指针都需要用智能指针去初始化    

七、性能问题
1、移动语义

// 移动构造函数快过复制构造函数,移动复制运算符快过拷贝赋值运算符;
shared_ptr pt1(new T);
shared_ptr pt2(std::move(p1)); // p1指针变成空,pt2所指向的内存引用计数仍为1;

 

标签:初始化,智能,new,shared,ptr,指针
来源: https://www.cnblogs.com/zhiminzeng/p/13060196.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有