练习12.19
定义你自己版本的StrBlobPtr,更新StrBlob类,加入恰当的friend声明及begin和end成员。
解答:
#include <iostream>
#include <vector>
#include <string>
#include <memory>
using namespace std;
class StrBlobStr;
class StrBlob{
public:
friend StrBlobStr;
<span style="white-space:pre"> </span>StrBlob* begin(){
<span style="white-space:pre"> </span>return this;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>StrBlob* end(){
<span style="white-space:pre"> </span>return this + data->size();
<span style="white-space:pre"> </span>}
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
size_type size() const{ return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const string &t)const{ data->push_back(t); }
void pop_back()const;
string& front();
string& back();
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string &msg) const;
};
StrBlob::StrBlob() :data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)){}
void StrBlob::check(size_type i, const string &msg) const{
if (i >= data->size()){
throw out_of_range(msg);
}
}
string& StrBlob::front(){
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back(){
check(0, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()const{
check(0, "pop_back on empty SteBlob");
data->pop_back();
}
class StrBlobStr{
public:
StrBlobStr() :curr(0){}
StrBlobStr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz){}
string &deref() const;
StrBlobStr &incr();
private:
shared_ptr<vector<string>> check(size_t , const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
shared_ptr<vector<string>> StrBlobStr::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;
}
string& StrBlobStr::deref() const{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobStr& StrBlobStr::incr(){
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
继续抄书上的代码,不过书上的代码在编译的时候会报错。
因为StrBolbStr的类型在StrBolb仅仅是声明,所以不能创建对象,只能创建指针(或引用)。
这样的话,begin和end一点存在的意义都没有。
练习12.20
编写程序,逐行读入一个输入文件,将内容存入一个StrBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素。
解答:
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <fstream>
using namespace std;
class StrBlobStr;
class StrBlob{
public:
friend StrBlobStr;
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
size_type size() const{ return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const string &t)const{ data->push_back(t); }
void pop_back()const;
string& front();
string& back();
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string &msg) const;
};
class StrBlobStr{
public:
StrBlobStr() :curr(0){}
StrBlobStr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz){}
string &deref() const;
StrBlobStr &incr();
private:
shared_ptr<vector<string>> check(size_t, const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
StrBlob::StrBlob() :data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)){}
void StrBlob::check(size_type i, const string &msg) const{
if (i >= data->size()){
throw out_of_range(msg);
}
}
string& StrBlob::front(){
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back(){
check(0, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()const{
check(0, "pop_back on empty SteBlob");
data->pop_back();
}
shared_ptr<vector<string>> StrBlobStr::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;
}
string& StrBlobStr::deref() const{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobStr& StrBlobStr::incr(){
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
void process(istream& in){
StrBlob file_content;
string line;
while (getline(in, line)){
file_content.push_back(line);
}
StrBlobStr print_obj(file_content, 0);
for (int i = 0; i != file_content.size(); i++, print_obj.incr()){
cout << print_obj.deref() << endl;
}
}
int main(){
ifstream in("test.txt");
process(in);
}
练习12.21
也可以这样编写StrBlobPtr的deref成员:
std::string& deref() const{
return (*check(curr, "dereference past end"))[curr];
}
你认为哪个版本更好?为什么?
解答:这样的确也是可以的,不过这样写对于代码的理解带来了不必要的障碍。
所以还是觉得,还是分开写的版本比较好。
练习12.22
为了能让StrBlobPtr使用const StrBlob,你觉得应该如何修改?
定义一个名为ConstStrBlobPtr的类,使其能够指向const StrBlob。
解答:
对StrBlobPtr的构造函数做点手脚即可。
StrBlobStr(const StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz){}