智能指针详解

智能指的作⽤是管理⼀个指针,避免申请的空间在函数结束时忘记释放,造成内存泄漏这种情况的发⽣。因为智能指针就是⼀个类,当超出了类的作⽤域是,类会⾃动调⽤析构函数,析构函数会⾃动释放资源。定义在头文件memory。

1.auto_ptr(拥有严格对象所有权语义的智能指针)

C++98 的⽅案,C11 已抛弃。

auto_ptr 是通过由 new 表达式获得的对象,并在 auto_ptr 自身被销毁时删除该对象的智能指针。复制 auto_ptr ,会复制指针并转移所有权给目标:auto_ptr 的复制构造和复制赋值都会修改其右侧参数,而且“副本”不等于原值。

#include<iostream>
using namespace std;

int main()
{
	auto_ptr<string>p1(new string("hello"));
	auto_ptr<string>p2;
	p2 = p1;
}

这个代码运行起来不会报错,但是当有程序运行时访问了p1,那么就会报错了,因为p1对对象的所有权已经被p2剥夺了。所以 auto_ptr 的缺点是:存在潜在的内存崩溃问题!

2. unique_ptr(替换auto_ptr,拥有独有对象所有权的智能指针)

unique_ptr独有的操作
unique_ptr<T>u1空unique_ptr,可以指向类型为T的对象,u1会使用delete来释放它的指针;u2会使用一个类型为D的可调用对象来释放它的指针
unique_ptr<T,D>u2
unique_ptr<T,D>u(d)空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete。
u=nullptr释放u指向的对象,将u置空
u.release()u放弃对指针的控制权,返回指针,并将u置空
u.reset()释放u指向的对象
u.reset(q)如果提供的内置指针q,令u指向这个对象;否则将u置空
u.reset(nullptr)

std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。unique_ptr 实现独占式拥有或严格拥有概念,保证同⼀时间内只有⼀个智能指针可以指向该对象

  • 在下列两者之一发生时用关联的删除器释放对象
    • 销毁了管理的 unique_ptr 对象
    • 通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。

通过调用 get_deleter()(ptr) ,用潜在的为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。

unique_ptr的初始化必须采用直接初始化的方式。

	unique_ptr<double>p1;//可以指向一个double的unique_ptr
	unique_ptr<int>p2(new int(42));//p2指向一个值为42的int

并且unique_ptr不支持普通的拷贝或者赋值操作。

unique_ptr<string>p1;
	unique_ptr<string>p2(p1));//错误,不支持拷贝
	unique_ptr<string>p3;
	p3 = p1;					//错误,不支持赋值

通过调用release或reset可以将指针的所有权从一个(非const)unique_ptr转义给另一个unique:

    //将所有权从p1转移给p2
	unique_ptr<string>p2(p1.releasse());//release将p1置空
	unique_ptr<string>p3(new string("text"));
	//将所有权从p3转移给p2
	p2.reset(p3.release());//reset释放了p2原来指向的内存

注意:使用release时,记得保存返回的指针,不然会丢失指针,并无法释放内存。

unique_ptr不能拷贝的规则有一个例外:就是我们可以拷贝或赋值一个将要被销毁的unique_ptr。

unique_ptr<int>clone(int p) {
		return unique_ptr<int>(new int(p));
	}

3. shared_ptr(共享型,强引)

shared_ptr和unique_ptr都支持的操作
shared_ptr<T>sp空智能指针,可以指向类型为T的对象
unique_ptr<T>up
p将p用作一个条件判断,若p指向一个对象,则为true
*p解引用p,获得它指向的对象
p->mem等价于(*p).mem
p.get()返回p中保存的指针
swap(p,q)交换p,q中的指针
p.swap(q)
shared_ptr独有的操作
make_shared<T>(args)返回一个shared_ptr,指向一个动态分配类型为T的对象,使用args初始化此对象
shared_ptr<T>p(q)p是shared_ptr q的拷贝:此操作会递增q中的计数器。q中的指针必须能转换为T*。
p=qp和q都是shared_ptr,所保存的指针必须能互相转换。此操作会递减p的引用计数,递增q的引用计数
p.unique()若p.use_count()为1,返回true,否则发挥false
p.use_count()返回与p共享对象的智能指针数量;可能很慢,主要用于调试

shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性 (auto_ptr 是独占的),在使⽤引⽤计数的机制上提供了可以共享所有权的智能指针。

make_shared函数

最安全的分配和使用动态内存的方法就是调用一个make_shared的标准库函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。

使用make_shared:

//指向一个值为42的int的shared_ptr

shared_ptr<int>p3=make_shared<int>42;

//p4指向一个值为“9999999”的string

shared_ptr<string>p4=make_shared<string>(10,'9');

//p5指向一个值初始化的int,即,值为0

shared_ptr<int>p5=make_shared<int>();

通常使用auto定义一个对象来保存make_shared的结果。

shared_ptr拷贝和赋值时,其引用计数会增加,当计数器变为0时,自动释放自己管理的对象,当动态对象不在被使用时,也会自动释放动态对象,比如当智能指针离开函数作用域时。

shared_ptr和new结合使用

因为智能指针的构造函数是explicit(不支持隐式转换)的,所以用new指针初始化智能指针的时候,只能直接初始化:

shared_ptr<int>p1=new int(1024)                //错误

shared_ptr<int>p1(new int(1024))                //正确  

  1. 不要混合使用智能指针和普通指针
  2. 永远不要使用get初始化另一个智能指针或为智能指针赋值,如果这样做,这很容易导致空悬指针。

4.weak_ptr(弱引用)

weak_ptr 是⼀种不控制对象⽣命周期的智能指针,它指向⼀个 shared_ptr 管理的对象。进⾏该对象的内存管理的是那个强引⽤的 shared_ptr。

weak_ptr 只是提供了对管理对象的⼀个访问⼿段,它的构造和析构不会 引起引⽤记数的增加或减少。weak_ptr 是⽤来解决 shared_ptr 相互引⽤时的死锁问题。

weak_ptr
weak_ptr<T>w空weak_ptr可以指向类型为T的对象
weak_ptr<T>w(sp)与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的类型。
w=pp可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象
w.reset()将w置空
w.use_count()

与w共享对象的shared_ptr的数量

w.expired()若w.use_count()为0 ,返回true,否则返回false
w.lock()如果expired为true,返回一个空shared_ptr:否则返回一个执行w的对象的shared_ptr

当创建一个weak_ptr时,需要用一个shared_ptr来初始化它:

auto p=make_shared<int>(42);

weak_ptr<int>wp(p);                //wp弱共享p,p的引用计数未改变

当两个智能指针都是 shared_ptr 类型的时候,析构时两个资源引⽤计数会减⼀,但是两者引⽤计数还是为 1,导致跳出函数时资源没有被释放(的析构函数没有被调⽤),解决办法:把其中⼀个改为weak_ptr就可以。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值