本文共 6641 字,大约阅读时间需要 22 分钟。
weak_ptr类
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由一个shared_ptr管理的对象。将一个weak_ptr绑定到shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象还是会被释放weak_ptrw //空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/