问题描述
嗨,我正在阅读 C++ 入门第 5 版,并且对weak_ptr 部分有一些疑问。写的是
通过使用weak_ptr,我们不会影响给定StrBlob 指向的向量的生命周期。但是,我们可以阻止用户尝试访问不再存在的向量。
然后他们给出了以下代码作为示例:
#include<iostream>
#include<string>
#include<vector>
#include<memory>
#include<initializer_list>
using namespace std;
class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob():data(std::make_shared<std::vector<std::string>>()){
}
StrBlob(std::initializer_list<std::string> il):data(make_shared<vector<std::string>>(il)){
}
size_type size() const {
return data->size();
}
bool empty() const {
return data->empty();
}
void push_back(const std::string &t){
data->push_back(t);
}
std::string& front(){
check(0,"front on empty StrBlob");
return data->front();
}
std::string& front() const{
check(0,"front on const empty StrBlob");
return data->front();
}
std::string& back(){
check(0,"back on empty StrBlob");
return data->back();
}
std::string& back() const {
check(0,"back on const empty StrBlob");
return data->back();
}
void pop_back(){
check(0,"pop_back on empty StrBlob");
data->pop_back();
}
private:
std::shared_ptr<std::vector<std::string>> data;
void check(size_type i,const std::string &msg) const{
if(i >= data->size()){
throw out_of_range(msg);
}
}
StrBlobPtr begin();
StrBlobPtr end();
};
class StrBlobPtr {
public:
typedef std::vector<std::string>::size_type size_type;
StrBlobPtr():curr(0){
}
StrBlobPtr(StrBlob &a,size_type sz = 0):wptr(a.data),curr(sz){
}
std::string& deref() const {
auto p = check(curr,"dereference past end");
return (*p)[curr];
}
StrBlobPtr& incr(){
check(curr,"increment past end of StrBlobPtr");
++curr;
return *this;
}
std::shared_ptr<std::vector<std::string>> check(std::size_t i,const std::string &msg) const{
auto ret = wptr.lock();
if(!ret){
throw std::runtime_error("unbound StrBlobPtr");
}
if(i>= ret->size()){
throw std::out_of_range(msg);
}
return ret;
}
private:
std::weak_ptr<std::vector<std::string>> wptr;
size_type curr;
};
StrBlobPtr StrBlob::begin() {
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end() {
auto ret = StrBlobPtr(*this,data->size());
}
int main(){
return 0;
}
我的问题如下:
- 我们如何防止用户尝试访问不再存在的向量?我想不出一个用例,我们如何在这个例子中使用上面引用的语句?
- 此示例如何显示/验证我们可以防止用户尝试访问不再存在的向量? *如果这个例子没有显示他们所写的内容,那么为什么书中有这个例子?*请注意,我已经写了如果。
解决方法
1.我们如何防止用户尝试访问不再存在的向量?
我们可以通过将 weak_ptr
换成 shared_ptr
来防止它发生。 weak_ptr::lock()
就是这样做的。它原子地检查所指向的对象是否仍然存在并增加相应的 shared_ptr
引用计数,从而“阻止”从该点开始的任何可能的删除。
所以在这行之后:
auto ret = wptr.lock();
ret
将是拥有或不拥有对象的 shared_ptr
,只要 ret
存在,这一事实就不会改变。
然后通过一个简单的测试,您可以安全地检查是否有对象:
if(!ret){
/* no object anymore */
}
最后,函数执行 return ret;
,它返回它的一个副本,从而仍然防止对象被删除(引用计数再次增加然后减少)。因此,只要您拥有 shared_ptr
的实例,您就可以放心该对象将继续存在。
然而,这里有一个问题:
std::string& deref() const {
auto p = check(curr,"dereference past end");
return (*p)[curr];
}
这会返回对 std::string
内的 vector
的引用,在 p
超出范围后,该引用仅由 weak_ptr
持有,即潜在的悬空引用(即与悬空指针没有什么不同)。
2.此示例如何显示/验证我们可以阻止用户尝试访问不再存在的向量?
显然不是。直接忽略它。