博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++Primer : 第十二章 :智能指针weak_ptr类
阅读量:2433 次
发布时间:2019-05-10

本文共 6641 字,大约阅读时间需要 22 分钟。

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 = p //p可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象w.reset() //将w置为空w.use_count() //与w共享对象的shared_ptr的数量w.expired() //若w.use_count()为0,返回true,否则返回falsew.lock() //如果expired为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr

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

auto p = make_shared
(42);weak_ptr
wp(p); //wp弱共享p,p的引用计数未改变

由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock。此函数检查weak_ptr指向的对象是否存在。如果存在,lock返回一个指向共享对象的shared_ptr。

if (shared_ptr
np = wp.lock()){
//如果np不为空,则条件成立 //在if中,np与p共享对象}

核查指针类

我们将为StrBlob类定义一个伴随指针类。我们的指针类将命名为StrBlobPtr,会保存一个weak_ptr,指向StrBlob的data成员,这是初始化时提供给它的。通过使用weak_ptr,不会影响一个给定的StrBlob所指向的vector的生存期。但是,可以阻止用户访问一个不再存在的vector的企图。

StrBlobPtr会有两个数据成员:wptr或者为空,或者指向一个StrBlob中的vector;curr,保存当前对象所表示的元素的下标。类似它的伴随类StrBlob,我们的指针也有一个check成员来检查解引用StrBlobPtr是否安全:

//对于访问一个不存在元素的尝试,StrBlobPtr抛出一个异常class StrBlobPtr {
friend class StrBlob;public: StrBlobPtr() : curr(0) {
} StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {
} string& deref() const; StrBlobPtr& incr(); //前缀递增private: //若检查成功,check返回一个指向vector的shared_ptr shared_ptr
> check(size_t, const string&) const; //保存一个weak_ptr,意味着底层vector可能被销毁 weak_ptr
> wptr; size_t curr; //在数组中的当前位置};

默认构造函数生成一个空的StrBlobPtr。其构造函数初始化列表将curr显式初始化为0,并将wptr隐式初始化为一个空weak_ptr。

第二个构造函数接受一个StrBlob引用和一个可选的索引值。此构造函数初始化wptr,令其指向给定StrBlob对象的shared_ptr中的vector,并将curr初始化为sz的值。我们使用了默认参数,表示默认情况下将curr初始化为第一个元素的下标。

shared_ptr
> StrBlobPtr::check(size_t i, const string& msg) const {
auto ret = wptr.lock(); //vector还存在吗?若存在返回一个指向w的对象的shared_ptr if (!ret) throw runtime_error("unbound StrBlobPtr"); if (i >= ret->size()) throw out_of_range(msg); return ret; //否则,返回指向vector的shared_ptr}

如果vector已经销毁,lock将返回一个空指针。在本例中,任何vector的引用都会失败,于是抛出一个异常。否则,check会检查给定索引,如果索引值合法,check返回从lock获得的shared_ptr。

指针操作

定义名为deref和incr的函数,分别用来解引用和递增StrBlobPtr
deref成员调用check,检查使用vector是否安全以及curr是否在合法范围内:

string& StrBlobPtr::deref() const {
auto p = check(curr, "dereference past end"); return (*p)[curr]; //(*p)是对象所指的vector}

如果check成功,p就是一个shared_ptr,指向StrBlobPtr所指向的vector。表达式(*p)[curr]解引用shared_ptr来获得vector,然后使用下标运算符提取并返回curr位置上的元素。

//前缀递增:返回递增后的对象的引用StrBlobPtr& StrBlobPtr::incr() {
//如果curr已经指向容器的尾后位置,就不能递增它 check(curr, "increment past end of StrBlobPtr"); ++curr; //推进当前位置 return *this;}

为了访问data成员,我们的指针类必须声明为StrBlob的friend。我们还要为StrBlob类定义begin和end操作,返回一个指向它自身的StrBlobPtr:

class StrBlobPtr;class StrBlob{
StrBlobPtr begin(){
return StrBlobPtr(*this);} StrBlobPtr end(){
auto ret = StrBlobPtr(*this, data->size()); return ret; }}

定义你自己版本的StrBlobPtr,更新StrBlob类,加入适当的friend声明以及begin和end成员

#include 
#include
#include
#include
#include
using namespace std;//提前声明,StrBlob中的friend类声明所需class StrBlob {
friend class StrBlobPtr;public: typedef vector
::size_type size_type; StrBlob(); //默认构造函数分配一个空的vector //接受一个initializer_list的构造函数将其参数传递给对应的vector构造函数。此构造函数通过拷贝列表中的值来初始化vector中的元素 StrBlob(initializer_list
il); size_type size() const { return data->size(); } bool empty() const { return data->empty(); } //添加和删除元素 void push_back(const string& t) { data->push_back(t); } void pop_back(); //元素访问 string& front(); const string& front() const; string& back(); const string& back() const; //提供给StrBlobPtr的接口 StrBlobPtr begin(); StrBlobPtr end();private: shared_ptr
> data; //如果data[i]不合法则抛出一个异常 void check(size_type i, const string& msg) const;};inline StrBlob::StrBlob():data(make_shared
>()){ }inline StrBlob::StrBlob(initializer_list
il) : data(make_shared
>(il)) { };inline void StrBlob::check(size_type i, const string& msg) const { if (i >= data->size()) throw out_of_range(msg);}inline string& StrBlob::front() { //如果vector为空,check会抛出一个异常 check(0, "front on empty StrBlob"); return data->front();}inline const string& StrBlob::front() const{ //如果vector为空,check会抛出一个异常 check(0, "front on empty StrBlob"); return data->front();}inline string& StrBlob::back() { check(0, "back on empty StrBlob"); return data->back();}inline const string& StrBlob::back() const{ check(0, "back on empty StrBlob"); return data->back();}inline void StrBlob::pop_back() { check(0, "pop_back on empty StrBlob"); data->pop_back();}class StrBlobPtr { friend bool eq(const StrBlobPtr&, const StrBlobPtr&); //StrBlobPtr的比较操作public: StrBlobPtr() : curr(0) { } StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) { } string& deref() const; //指针操作 StrBlobPtr& incr(); //前缀递增 StrBlobPtr& decr(); //前缀递减private: //若检查成功,check返回一个指向vector的shared_ptr shared_ptr
> check(size_t, const string&) const; //保存一个weak_ptr,意味着底层vector可能被销毁 weak_ptr
> wptr; size_t curr; //在数组中的当前位置};inline shared_ptr
> StrBlobPtr::check(size_t i, const string& msg) const { auto ret = wptr.lock(); //vector还存在吗?若存在返回一个指向w的对象的shared_ptr if (!ret) throw runtime_error("unbound StrBlobPtr"); if (i >= ret->size()) throw out_of_range(msg); return ret; //否则,返回指向vector的shared_ptr}inline string& StrBlobPtr::deref() const { auto p = check(curr, "dereference past end"); return (*p)[curr]; //(*p)是对象所指的vector}//前缀递增:返回递增后的对象的引用inline StrBlobPtr& StrBlobPtr::incr() { //如果curr已经指向容器的尾后位置,就不能递增它 check(curr, "increment past end of StrBlobPtr"); ++curr; //推进当前位置 return *this;}//前缀递减:返回递减后对象的引用inline StrBlobPtr& StrBlobPtr::decr() { //如果curr已经为0,递减它就会产生一个非法下标 --curr; //递减当前位置 check(-1, "decrement past begin of StrBlobPtr"); return *this;}inline StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this);}inline StrBlobPtr StrBlob::end() { auto ret = StrBlobPtr(*this, data->size()); return ret;}inline bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) { auto l = lhs.wptr.lock(), r = rhs.wptr.lock(); //若底层的vector是同一个 if (l == r) //则两个指针都是空或者指向相同的元素 return (!r || lhs.curr == rhs.curr); else return false; //若指向不同vector,则不相等}inline bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) { return !eq(lhs, rhs);}int main() { StrBlob b1; { StrBlob b2 = { "a", "an", "the" }; b1 = b2; b2.push_back("about"); cout << b2.size() << endl; } cout << b1.size() << endl; cout << b1.front() << " " << b1.back() << endl; const StrBlob b3 = b1; cout << b3.front() << " " << b3.back() << endl; cout << endl; for (auto it = b1.begin(); neq(it, b1.end()); it.incr()) cout << it.deref() << endl; return 0;}

转载地址:http://itxmb.baihongyu.com/

你可能感兴趣的文章
Hibernate单向关联N-1
查看>>
Hibernate单向关联1-1
查看>>
jQuery自定义动画
查看>>
Spring-data-redis在shiro中的实例
查看>>
GUN C中__attribute__作用
查看>>
3、系统调用之SYSCALL_DEFINE分析
查看>>
linux的signal_pending及signal
查看>>
OBJDUMP用法
查看>>
c/cplusplus通用makefile
查看>>
JavaScript-密码强度
查看>>
【SSH】1366-InCorrect string value:'\xE9\x99\x88\xE6\x96\xB0...'for column 'name' at row 1
查看>>
SpringCloud前身之微服务
查看>>
纵览全局——SSH
查看>>
纵览全局——Mybatis
查看>>
PC端-中文转拼音后续问题
查看>>
第七章-面向对象技术
查看>>
Mybatis-略识之无
查看>>
ionic 前端 - 汉字转拼音
查看>>
Ionic-与时间有关的故事-localecompare()
查看>>
ionic -- 实现根据拼音字母搜索人员
查看>>