C++ 智能指针

头文件 #include < memory >

智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。

两种智能指针:
- shared_ptr 允许多个指针指向同一个对象。
- unique_ptr 独占所指向的对象。

weak_ptr:伴随类,它是一种弱引用,指向shared_ptr所管理的对象。

1. shared_ptr

shared_ptr<T> sp //空智能指针,可以指向类型为T的对象

unique_ptr<T> up 

shared_ptr独有的操作

操作含义
make_shared(args)返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象
shared_ptrp(q)p是shared_ptr q的拷贝;此操作会递增q中的计数器。q中的指针必须能转换为T*
p = qp和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数

1.1 make_shared函数

最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。

此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。

//指向一个值为42的int的shared_ptr
shared_ptr<int> p3 = make_shared<int>(42);

1.2 shared_ptr的拷贝和赋值

可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数

无论何时我们拷贝一个shared_ptr,计数器都会递增。

当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减。

一旦一个shared_ptr的计数器变为 0,它就会自动释放自己所管理的对象。

1.3 shared_ptr自动销毁所管理的对象

当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象。

它是通过另一个特殊的成员函数–析构函数完成销毁工作的。

shared_ptr的析构函数会递减它所指向的对象的引用计数。如果引用计数变为 0,shared_ptr的析构函数就会销毁对象,并释放它所占用的内存。

1.5 使用了动态生存期的资源的类

程序使用动态内存处于以下三种原因之一:
1. 程序不知道自己需要使用多少对象
2. 程序不知道所需对象的准确类型
3. 程序需要在多个对象间共享数据

1.6 shared_ptr和new结合使用

不能讲一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式。

shared_ptr<int> p1 = new int(1024); //错误,必须使用直接初始化形式

shared_ptr<int> p2(new int(1024)); //正确,使用了直接初始化形式

不要混合使用智能指针和普通指针
当将一个shared_ptr绑定到一个普通指针时,我们就将内存的管理责任交给了这个shared_ptr。一旦这样做了,我们就不应该再使用内置指针来访问shared_ptr所指向的内存了。

2. 智能指针和异常

一个简单地确保资源被释放的方法是使用智能指针。

如果使用智能指针,即使程序块过早结束,智能指针类也能确保在内存不再需要时将其释放:

void f()
{
    shared_ptr<int> sp(new int(42));  //分配一个新对象

    //这段代码抛出一个异常,且在f中未被捕获
}   //在函数结束时shared_ptr自动释放内存

如果使用内置指针管理内存,且在new之后在对应的delete之前发生了异常,则内存不会被释放:

void f()
{
    int *ip = new int(42);  //动态分配一个新对象

    //这段代码抛出一个异常,且在f中未被捕获
    delete ip;  //在退出之前释放内存
}   

3. unique_ptr

与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。

当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针上。类似shared_ptr,初始化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(new string("Stegosaurus"));

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

unique_ptr<string> p3;

p3 = p2;    //错误,unique_ptr不支持赋值
操作含义
u.release()u放弃对只指针的控制权,返回指针,并将u置为空
u.reset()释放u指向的对象
u.reset(q)如果提供了内置指针q,令u指向这个对象;否则将u置为空

不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个unique_ptr转移给另一个unique_ptr:

//将所有权从p1转移给p2
unique_ptr<string> p2(p1.release());  //release将p1置为空

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

release成员返回unique_ptr当前保存的指针并将其置为空。

reset成员接受一个可选的指针参数,令unique_ptr重新指向给定的指针。

3.1 传递unique_ptr参数和返回unique_ptr

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

例,从函数返回一个unique_ptr:

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

返回一个局部对象的拷贝:

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

3. weak_ptr

weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象。

将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。

一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象还是会被释放。

操作含义
weak_ptr w空weak_ptr可以指向类型为T的对象
weak_ptr w(sp)与shared_ptr sp 指向相同对象的weak_ptr。T必须能转换为sp指向的对象
w = pp可以是一个shared_ptr或一个weak_ptr
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直接访问对象,而必须调用lock。

此函数检查weak_ptr指向的对象是否仍存在。如果存在,lock返回一个指向共享对象的shared_ptr。

if (shared_ptr<int> np = wp.lock())
{
    //如果np不为空,则条件成立
    //在if中,np与p共享对象
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值