练习12.19
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include <sstream> 5 #include <set> 6 #include <map> 7 #include <algorithm> 8 #include <vector> 9 #include <algorithm> 10 #include <iterator> 11 #include <unordered_map> 12 #include <memory> 13 14 using namespace std; 15 16 class strBlobPtr { 17 public: 18 strBlobPtr() : curr(0) {} 19 strBlobPtr(strBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) {} 20 string & deref() const; 21 strBlobPtr &incr(); 22 private: 23 shared_ptr<vector<string>> check(size_t t, const string &str) const; 24 weak_ptr<vector<string>> wptr; 25 size_t curr; 26 }; 27 28 class strBlob { 29 friend void print(strBlob s); 30 friend class strBlobPtr; 31 public: 32 typedef vector<string>::size_type size_type; 33 strBlob(); 34 strBlob(initializer_list<string> il); 35 size_type size() const { return data->size(); } 36 bool empty() const { return data->empty(); } 37 void push_back(const string &t); 38 void pop_back(); 39 const string &front(); 40 const string &back(); 41 strBlobPtr begin() { return strBlobPtr(*this); } 42 strBlobPtr end() { return strBlobPtr(*this, data->size()); } 43 private: 44 shared_ptr<vector<string>> data; 45 void check(size_type i, const string &msg) const; 46 }; 47 48 void print(strBlob s); 49 50 int main() 51 { 52 strBlob p1({ "asd", "qew", "jkl" }); 53 print(p1); 54 p1.push_back("dqw"); 55 print(p1); 56 p1.pop_back(); 57 p1.pop_back(); 58 print(p1); 59 cout << endl; 60 cout << p1.front() << endl; 61 cout << p1.back() << endl; 62 system("pause"); 63 return 0; 64 } 65 66 strBlob::strBlob() : data(make_shared<vector<string>>()) {} 67 strBlob::strBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {} 68 void strBlob::push_back(const string & t) 69 { 70 data->push_back(t); 71 } 72 void strBlob::pop_back() 73 { 74 check(0, "pop_back on empty StrBlob"); 75 data->pop_back(); 76 } 77 const string & strBlob::front() 78 { 79 check(0, "front on empty StrBlob"); 80 return data->front(); 81 // TODO: 在此处插入 return 语句 82 } 83 const string & strBlob::back() 84 { 85 check(0, "back on empty StrBlob"); 86 return data->back(); 87 // TODO: 在此处插入 return 语句 88 } 89 90 91 void strBlob::check(size_type i, const string & msg) const 92 { 93 if (i >= data->size()) 94 throw out_of_range(msg); 95 } 96 97 void print(strBlob s) 98 { 99 for (auto c : *(s.data)) 100 cout << c << endl; 101 cout << endl; 102 } 103 104 string & strBlobPtr::deref() const 105 { 106 auto p = check(curr, "dereference past end"); 107 return (*p)[curr]; 108 // TODO: 在此处插入 return 语句 109 } 110 111 strBlobPtr & strBlobPtr::incr() 112 { 113 check(curr, "increment past end of strBlobPtr"); 114 ++curr; 115 return *this; 116 // TODO: 在此处插入 return 语句 117 } 118 119 shared_ptr<vector<string>> strBlobPtr::check(size_t t, const string & str) const 120 { 121 auto ret = wptr.lock(); 122 if (!ret) 123 throw runtime_error("unbound strBlobPtr"); 124 if (t >= ret->size()) 125 throw out_of_range(str); 126 return ret; 127 }
练习12.20
1 //my_StrBlob.h 2 #ifndef MY_STRBLOB_H 3 #define MY_STRBLOB_H 4 #include <vector> 5 #include <string> 6 #include <memory> 7 #include <initializer_list> 8 #include <stdexcept> 9 using std::vector; 10 using std::string; 11 using std::shared_ptr; 12 using std::make_shared; 13 using std::weak_ptr; 14 using std::initializer_list; 15 using std::runtime_error; 16 using std::out_of_range; 17 18 // 提前声明,StrBlob中的友类声明所需 19 class StrBlobPtr; 20 21 class StrBlob { 22 friend class StrBlobPtr; 23 public: 24 typedef vector<string>::size_type size_type; 25 StrBlob(); 26 StrBlob(initializer_list<string> il); 27 size_type size() const { return data->size(); } 28 bool empty() const { return data->empty(); } 29 // 添加删除元素 30 void push_back(const string &t) {data->push_back(t); } 31 void pop_back(); 32 // 元素访问 33 string& front(); 34 const string& front() const; 35 string& back(); 36 const string& back() const; 37 38 // 提供给StrBlobPtr的接口 39 StrBlobPtr begin(); //定义了StrBlobPtr后才能定义这两个函数 40 StrBlobPtr end(); 41 private: 42 shared_ptr<vector<string>> data; 43 // 如果data[i]不合法,抛出一个异常 44 void check(size_type i, const string &msg) const; 45 }; 46 47 inline StrBlob::StrBlob(): data(make_shared<vector<string>> ()) { } 48 StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>> (il)) { } 49 50 inline void StrBlob::check(size_type i, const string &msg) const 51 { 52 if (i >= data->size()) 53 throw out_of_range(msg); 54 } 55 56 inline string& StrBlob::front() 57 { 58 check(0, "front on empty StrBlob"); 59 return data->front(); 60 } 61 62 // const版本front 63 inline const string& StrBlob::front() const 64 { 65 check(0, "front on empty StrBlob"); 66 return data->front(); 67 } 68 69 inline string& StrBlob::back() 70 { 71 check(0, "back on empty StrBlob"); 72 return data->back(); 73 } 74 75 // const版本back 76 inline const string& StrBlob::back() const 77 { 78 check(0, "back on empty StrBlob"); 79 return data->back(); 80 } 81 82 inline void StrBlob::pop_back() 83 { 84 check(0, "pop_back on empty StrBlob"); 85 return data->pop_back(); 86 } 87 88 //当试图访问一个不存在的元素时,StrBlobPtr抛出一个异常 89 class StrBlobPtr { 90 friend bool eq(const StrBlobPtr&, const StrBlobPtr&); 91 public: 92 StrBlobPtr() : curr(0) { } 93 StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { } 94 95 string& deref() const; 96 StrBlobPtr& incr(); //前缀递增 97 StrBlobPtr& decr(); //前缀递减 98 private: 99 // 若检查成功,check返回一个指向vector的shared_ptr 100 shared_ptr<vector<string>> check(size_t, const string&) const; 101 // 保存一个weak_ptr,意味着底层vector可能会被销毁 102 weak_ptr<vector<string>> wptr; 103 size_t curr; 104 }; 105 106 inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const 107 { 108 auto ret = wptr.lock(); //vector还存在吗? 109 if (!ret) 110 throw runtime_error("unbound StrBlobPtr"); 111 if (i >= ret->size()) 112 throw out_of_range(msg); 113 return ret; //否则,返回指向vector的shared_ptr 114 } 115 116 inline string& StrBlobPtr::deref() const 117 { 118 auto p = check(curr, "dereference past end"); 119 return (*p)[curr]; //(*p)是对象所指的vector 120 } 121 122 // 前缀递增:返回递增后的对象的引用 123 inline StrBlobPtr& StrBlobPtr::incr() 124 { 125 // 如果curr已经指向容器的尾后位置,就不递增它 126 check(curr, "increment psat end of StrBlobPtr"); 127 ++curr; //推进当前位置 128 return *this; 129 } 130 131 // 前缀递减,返回递减后的对象的引用 132 inline StrBlobPtr& StrBlobPtr::decr() 133 { 134 // 如果curr已经为0,递减它就会产生一个非法下标 135 --curr; //递减当前位置 136 check(-1, "decrement past begin of StrBlobPtr"); 137 return *this; 138 } 139 140 // StrBlob的begin和end成员的定义 141 inline StrBlobPtr StrBlob::begin() 142 { 143 return StrBlobPtr(*this); 144 } 145 146 inline StrBlobPtr StrBlob::end() 147 { 148 auto ret = StrBlobPtr(*this, data->size()); 149 return ret; 150 } 151 152 // StrBlobPtr的比较操作 153 inline bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs) 154 { 155 auto l = lhs.wptr.lock(), r = rhs.wptr.lock(); 156 if (l == r) 157 return (!r || lhs.curr == rhs.curr); 158 else 159 return false; 160 } 161 162 inline bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs) 163 { 164 return !eq(lhs, rhs); 165 } 166 #endif 167 //main.cc 168 #include <iostream> 169 #include <fstream> 170 using std::cout; 171 using std::endl; 172 using std::ifstream; 173 174 #include "my_StrBlob.h" 175 176 int main(int argc, char **argv) 177 { 178 ifstream in(argv[1]); 179 if (!in) { 180 cout<<"Open input file failed"<<endl; 181 return -1; 182 } 183 184 StrBlob b; 185 string s; 186 while (getline(in, s)) 187 b.push_back(s); 188 189 for (auto it = b.begin(); neq(it, b.end()); it.incr()) 190 cout<<it.deref()<<endl; 191 192 return 0; 193 }
练习12.21
书中的方式更好一些。将合法性检查与元素获取的返回语句分离开来,代码更清晰易读,当执行到第二条语句时,已确保p是存在的vector,curr是合法的位置,可安全地获取元素并返回。这种清晰的结构也更有利于修改不同的处理逻辑。
而本题中的版本将合法性检查和元素获取及返回合在一条语句中,不易读,也不易修改。
练习12.22
1 StrBlobStr(const StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz){}