C++智能指针shared_ptr、unique_ptr使用

背景

为什么使用动态内存
程序不知道自己需要多少对象;
程序不知道对象的准确类型;
程序需要在多个对象之间共享数据;

动态内存与智能指针

我们知道c++需要注意的地方之一就是对内存的管理,动态内存的使用经常会出现内存泄漏,或者产生引用非法内存的指针
新的标准库提供了两种智能指针类型来管理动态对象:

(1)shared_ptr 允许多个指针指向同一个对象
(2)unique_ptr 独占所指向的对象

定义在memory头文件中,他们的作用在于会自动释放所指向的对象。

智能指针的本质

智能指针的实质是一个对象,行为却表现的像一个指针

1. make_shared函数

什么是make_shared函数,他的作用是什么呢?

    make_shared函数是一个安全的分配和使用动态内存的方法。他会在动态内存中分配一个对象并初始化它,返回值是一个指定类型的shared_ptr,同样也定义在memory的头中。

//指向一个值为42的int的shared_ptr
shared_ptr<int> p = make_shared<int> (42);
//指向一个值为"999"的string
shared_ptr<string> q = make_shared<string> (3, '9');
//指向一个值初始化的int,即值为0
shared_ptr<int> w = make_shared<int> ();

make_shared怎么初始化

    make_shared用其参数来构造给定类型的对象,也就是说,我们的参数,必须符合给定类型的某一构造函数,不传参就默认初始化。

与shared_ptr的区别,为什么使用make_shared更好

    他相比shared_ptr减少了内存分配的次数,而内存分配的代价较高;他会立即获得申请的裸指针,不会造成内存泄漏。

make_shared的缺点

    当构造函数是保护或私有的时,无法使用make_shared;对象调额内存可能无法及时回收。

2. shared_ptr常见操作

shared_ptr也是一个模板,所以我们在创建的时候,需要提供指针指向的类型。

shared_ptr<string> p1;  //指向string
shared_ptr<list<int>> p2;   //指向int的list

或者

shared_ptr<int> p1(new int(1));//直接初始化
shared_ptr<int> p2 = new int(1);//错误,int是内置类型

默认初始化的智能指针为一个空指针,智能指针的使用类似于普通指针:

if (p1 &&p1->empty()) //如果p1不为空且p1指向一个空string 
{
    *p1 = "lvbai";  //赋值
}

3. unique_ptr基本操作

unique_ptr的直观认知应该就是“独占”、“拥有”了吧。它的意思就是某个时刻只能有一个unique_ptr指向一个给定的对象,即不能拷贝和赋值

int* p (new int(3));
shared_ptr<int> p1(p);
auto p2 = p1; //ok
unique_ptr<int> p3(p);
unique_ptr<int> p4(p); //ok,智能指针毕竟只是一个帮助你管理的一个工具,它并不能知道有多少初始化的动作
unique_ptr<int> p5 = p3; //error

初始化

unique_ptr没有类似make_shared的操作,只能直接初始化

unique_ptr<int> p(new int(1024)); //ok
unique_ptr<int> p1 = new int; //error
unique_ptr<int> p2(p); //error

定义自己的释放操作

方式一

shared_ptr<T> p(q) //p管理内置指针q,q必须指向new分配的内存,且能够转换为T*类型

shared_ptr<T> p(u) //p从unique_ptr u那里接管了对象的所有权,并将u置空

shared_ptr<T> p(q, d) //p接管了内置指针q所指向的对象的所有权,q必须能够转换为T*类型。p将使用可调用对象d来代替delete

shared_ptr<T> p(p2, d) //p是shared_ptr p2的拷贝,调用d来代替delete

//删除器必须接受所指定类型的参数,如,上述中就要接受一个类型为T*的参数

p.reset() 
p.reset(q)
p.reset(q, d)
//若p是唯一指向其对象的shared_ptr,reset会释放此对象。若传递了可选的参数内置指针q,会令p指向q,否则会将p置空。若还传递了参数d,则会调用d而不是delete来释放q

方式二

//例如:
void del(int* p)
{...}

shared_ptr<int> p(new int(1), del);
shared_ptr<int> p(new int, del);

使用示例

shared_ptr<int> a = make_shared<int>(22);

cout << "a addr:" << a << " a value:" <<  *a << " " << a.use_count() << endl;

a.reset();

cout << "a use count: " << a.use_count() << endl;  //指针使用次数

在这里插入图片描述

unique_ptr常见操作

unique_pre<T> p1; //空unique_ptr,可以指向类型为T的对象,p1会使用delete来释放它的指针,p2会使用一个类型为D的可调用对象来释放它的指针  

unique_ptr<T, D> p2; 
unique_ptr<T, D> p(d); //空unique_ptr,指向类型为T的对象,用类型为D的对象d来代替delete

p = nullptr; //释放p指向的对象,将p置为空
p.release(); //p放弃对指针的控制权,返回指针,并将p置空
p.reset(); //释放p所指向的对象
p.reset(q); //如果提供了内置指针q,令p指向这个对象;
p.reset(nullptr); 
  • 虽然我们不能拷贝和赋值,但我们可以调用上述所说的reset和release将指针的所有权从一个(非const)unqiue_ptr转移给另一个unique_ptr
//将所有权从p1转移给p2
unique_ptr<string> p2(p1.release());
p2.reset(p1.release());
  • 单纯调用release是错误的
p.release(); //错误,release放弃了控制权不会释放内存,丢失了指针
auto q = p.release(); //正确,记得delete掉q
  • 特殊的版本
    unique_ptr针对new出来的数组特殊化,是一个特殊化的版本
unique_ptr<int []> q(new int[10]);
q.release(); //自动用delete[]销毁其指针释放内存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值