【C++ Primer 习题集】(第5版)
练习12.19:定义你自己版本的StrBlobPtr,更新StrBlob类,加入恰当的friend声明及begin和end成员。
StrBlob是一个用于存储字符串类的变长容器,在访问、尾部添加、尾部删除时带有下标越界检查。StrBlob与自定义的指针类StrBlobPtr配合使用,来完成常见的容器操作。
参考代码:
#include<algorithm>
#include<string>
#include<vector>
#include<initializer_list>
#include<memory>
#include<stdexcept>
#include<iostream>
#pragma warning(disable:4996)
using std::string; using std::vector; using std::make_shared; using std::shared_ptr; using std::weak_ptr; using std::size_t;
using std::initializer_list; using std::out_of_range; using std::runtime_error; using std::cin; using std::cout; using std::endl;
class StrBlob {
friend class StrBlobPtr;
public://公有成员
StrBlob() { data = make_shared<vector<string>>(); }//参数为空的构造函数
StrBlob(const initializer_list<string>& i) { data = make_shared<vector<string>>(i); }//包含一个initializer_list作参数的构造函数
size_t size() const { return data->size(); }//返回已存储字符串数量的大小。
bool empty() const { return data->empty(); }//返回容器是否为空
string& front() const { return data->front(); }//返回容器最前端的字符串
string& back() const { return data->back(); }//返回容器最后端的字符串
void emplace_back(const string& s) { data->emplace_back(s); }//在尾部放入新字符串(C++11起)
void push_back(const string& s) { data->push_back(s); }//在尾部放入新字符串
void pop_back() { check_oor(0, "ERROR: Popping back on an empty StrBlob."); data->pop_back(); }//弹出(删除)最尾端的字符串
void clear() { data->clear(); }//清除全部已存储的字符串
bool operator==(const StrBlob& b) { return *this->data == *b.data; }//重定义==运算符,以便能够通过==方便地判断两个StrBlob是否相等
string& operator[](const size_t& n) { check_oor(n, "ERROR: Subscript out of range."); return (*data)[n]; }//重定义[]运算符,以便能够像访问数组一样访问每个保存的字符串。返回非常量时,允许通过该运算符赋值。
const string& operator[](const size_t& n) const { check_oor(n, "ERROR: Subscript out of range."); return (*data)[n]; }重定义[]运算符,以便能够像访问数组一样访问每个保存的字符串
shared_ptr<vector<string>>& address() { return data; }
private://私有成员
shared_ptr<vector<string>> data;//数据存储区域(指针)
void check_oor(const size_t& s, const string& msg) const { if (s >= data->size())throw out_of_range(msg); }//检查下标是否越界,如果是则抛出错误
};
class StrBlobPtr {
public:
StrBlobPtr() {};//构造函数
StrBlobPtr(const StrBlob& s) { p = s.data; };//构造函数
StrBlobPtr(const shared_ptr<vector<string>>& s) { p = s; }//构造函数
void point_to(const StrBlob& s) { p = s.data; }//改变StrBlobPtr指向的StrBlob对象
void point_to(const shared_ptr<vector<string>>& s) { p = s; }//改变StrBlobPtr指向的StrBlob对象
vector<string>& operator*() const { check_notnull("The StrBlobPtr points to no objects."); return *p.lock(); }//重定义*运算符,可通过该运算符直接对指向的StrBlob的用于存储字符串的vector进行操作
shared_ptr<vector<string>> operator->() const { check_notnull("The StrBlobPtr points to no objects."); return p.lock(); }//重定义*运算符,可通过该运算符直接对指向的StrBlob的用于存储字符串的vector进行操作
private:
weak_ptr<vector<string>> p;//指针,用于指向StrBlob的data私有对象
void check_notnull(const string& msg) const { if (p.expired())throw runtime_error(msg); }//检查指向的对象是否已销毁
};
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0);
StrBlob b1, b2, b3;
b1.emplace_back("sin"), b1.emplace_back("cos"), b1.emplace_back("tan");
cout << b1[0] << ' ' << b1[1] << ' ' << b1[2] << '\n';
b1[0] = "SIN"; cout << b1[0] << '\n'; b1[0] = "sin";
b2 = b1; cout << b2[0] << ' ' << b2[1] << ' ' << b2[2] << '\n';
b2.emplace_back("cot"), b2.emplace_back("sec"), b2.emplace_back("csc");
cout << b1[0] << ' ' << b1[1] << ' ' << b1[2] << ' ' << b1[3] << ' ' << b1[4] << ' ' << b1[5] << '\n';
cout << (b1 == b3) << '\n';
StrBlobPtr p(b1);
cout << (*p).front() << '\n';
p = b3.address(); cout << (*p).empty() << '\n';
p.point_to(b2); cout << p->back() << endl;
system("pause");
return 0;
}