weak_ptr 是一种不控制所指向对象生存期的智能指针,它指向有一个 shared_ptr 管理的对象。将一个 weak_ptr 绑定到 shared_ptr 不会改变 shared_ptr 的引用计数。一旦最后一个指向对象的 shared_ptr 被销毁,对象就会被释放。即使有 weak_ptr 指向对象,对象也还是会被释放。
因此不能直接用 weak_ptr 访问对象,而必须调用 lock 检查其指向的对象是否仍存在。如果存在,lock 返回一个指向共享对象的 shared_ptr。因此,只要此 shared_ptr 存在,它所指向的底层对象就会一直存在。
使用 sared_ptr 实现的对象共享底层数据类 StrBlob
class StrBlobPtr;
class StrBlob {
public:
friend class StrBlobPtr;
// 返回指向首元素和尾后元素的 StrBlobPtr
StrBlobPtr begin();
StrBlobPtr end();
using size_type = vector<string>::size_type;
StrBlob():data(make_shared<vector<string>>()){}
StrBlob(initializer_list<string> il):data(make_shared<vector<string>>(il)) {}
// 类属性
size_type size() const {
return data->size();
}
bool empty() const {
return data->empty();
}
// 添加和删除元素
void push_back(const string& str) {
data->push_back(str);
}
void pop_back() {
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
// 访问元素,非常量版本
string& front() {
check(0, "front on empty StrBlob");
return data->front();
}
string& back() {
check(0, "back on empty StrBlob");
return data->back();
}
// 访问元素,const版本
const string& front() const {
check(0, "front on empty StrBlob");
return data->front();
}
const string& back() const {
check(0, "back on empty StrBlob");
return data->back();
}
// print
void print(const string& msg) const {
cout << msg << "[ ";
for(size_type i=0; i<size(); i++) {
cout << data->at(i) << " ";
}
cout << "]";
cout << endl;
}
private:
shared_ptr<vector<string>> data;
// 核查索引是否在有效范围内
void check(size_type i, const string& msg) const {
if( i >= size() ) {
throw out_of_range(msg);
}
}
};
为 StrBlob 定义一个伴随指针类,保存一个 weak_ptr, 指向 StrBlob 的 data 成员。
class StrBlobPtr {
public:
StrBlobPtr():curr(0) {}
StrBlobPtr(StrBlob& b, size_t cur=0):wptr(b.data),curr(cur) {}
// 解引用
string& deref() const {
auto ret = check(curr, "dereference past end");
return (*ret)[curr];
}
// 自增
StrBlobPtr& incr() {
check(curr, "increase past end of StrBlobPtr");
++curr;
return *this;
}
private:
// 核查,若成功,返回一个指向vector的shared_ptr
shared_ptr<vector<string>> check(size_t i, const string& msg) const {
auto ret = wptr.lock();
if( !ret ) {
throw runtime_error("unbound StrBlobPtr");
}
if( i >= ret->size() ) {
throw out_of_range("msg");
}
return ret;
}
weak_ptr<vector<string>> wptr; // 指向vector
size_t curr; // 在数组中的位置
};
StrBlobPtr StrBlob::begin() {
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end() {
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
测试代码
void WeakPtrTest1() {
StrBlob sb1({"apple", "banalan", "juce"});
{
StrBlob sb2 = sb1;
}
auto iter = sb1.begin();
auto itere = sb1.end();
string str = iter.deref();
iter.incr();
str = iter.deref();
iter.incr();
str = iter.deref();
iter.incr();
str = iter.deref();
return;
}
C++ primer中文版 第五版 12章