Contents
strblob类
strblob.h中:
#include<initializer_list>
#include<string>
#include<memory>
#include<vector>
using namespace std;
class strblobptr; //先声明类
class conststrblobptr;
class strblob
{
friend class strblobptr;
friend class conststrblobptr;
public:
typedef vector<string>::size_type size_type;
strblob() : data(make_shared<vector<string>>()) {};
strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
bool empty() const { return data->empty(); }
//添加和删除元素
void push_back(const string& t) { data->push_back(t); };
void pop_back();
//元素访问
string& front();
const string& front() const;
string& back();
const string& back() const;
//迭代器操作
strblobptr begin();
strblobptr end();
private:
//strblob类的底层是一个vector<string>
shared_ptr<vector<string>> data;
//如果data[i]不合法,抛出一个异常
void check(size_type i, const string& msg) const;
};
class strblobptr
{
friend bool eq(const strblobptr& lhs, const strblobptr& rhs);
friend bool neq(const strblobptr& lhs, const strblobptr& rhs);
public:
strblobptr() : curr(0) {};
strblobptr(strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
string& deref() const; //访问指针所指元素
strblobptr& incr(); //递增指针
private:
shared_ptr<vector<string>> check(size_t, const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
bool eq(const strblobptr& lhs, const strblobptr& rhs);
bool neq(const strblobptr& lhs, const strblobptr& rhs);
class conststrblobptr
{
public:
conststrblobptr() : curr(0) {};
conststrblobptr(const strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
string& deref() const; //访问指针所指元素
conststrblobptr& incr(); //递增指针
private:
shared_ptr<vector<string>> check(size_t, const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
strblob.cpp中:
#include "strblob.h"
#include<stdexcept>
//===== strblob =====
void strblob::check(size_type i, const string& msg) const
{
if (i >= data->size())
throw out_of_range(msg); //throw索引越界的异常
}
//访问元素
string& strblob::front()
{
check(0, "front on empty strblob");
return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
check(0, "front on empty strblob");
return data->front();
}
string& strblob::back()
{
check(0, "front on empty strblob");
return data->back();
}
const string& strblob::back() const
{
check(0, "front on empty strblob");
return data->back();
}
//删除元素
void strblob::pop_back()
{
check(0, "pop_back on empty strblob");
return data->pop_back();
}
//迭代器操作
strblobptr strblob::begin()
{
return strblobptr(*this);
}
strblobptr strblob::end()
{
auto ret = strblobptr(*this, data->size());
return ret;
}
// ===== strblobptr =====
shared_ptr<vector<string>> strblobptr::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& strblobptr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
strblobptr& strblobptr::incr()
{
check(curr, "increment past end of strblobptr");
++curr;
return *this;
}
// StrBlobPtr 的比较操作
bool eq(const strblobptr& lhs, const strblobptr& rhs) {
auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
// 若底层的 vector 是同一个
if (l == r)
// 则两个指针都是空,或者指向相同元素时,它们相等
return (!r || lhs.curr == rhs.curr);
else
return false; // 若指向不同 vector,则不可能相等
}
bool neq(const strblobptr& lhs, const strblobptr& rhs) {
return !eq(lhs, rhs);
}
// ===== conststrblobptr =====
shared_ptr<vector<string>> conststrblobptr::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& conststrblobptr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
conststrblobptr& conststrblobptr::incr()
{
check(curr, "increment past end of strblobptr");
++curr;
return *this;
}
TextQuery类
TextQuery.h
#include<vector>
#include<string>
#include<set>
#include<map>
#include<fstream>
#include<memory>
using namespace std;
class QueryResult;
class TextQuery
{
friend class QueryResult;
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream&) : file(new vector<string>) {};
QueryResult query(const string& word) const;
private:
shared_ptr<vector<string>> file;
map<string, shared_ptr<set<line_no>>> wm;
};
class QueryResult
{
friend ostream& print(ostream&, const QueryResult&);
public:
using line_no = vector<string>::size_type;
using line_it = set<line_no>::const_iterator;
QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f) : sought(s), lines(p), file(f) {};
line_it begin() const { lines->begin(); };
line_it end() const { lines->end(); };
shared_ptr<vector<string>> get_file() { return file; };
private:
string sought;
shared_ptr<set<line_no>> lines;
shared_ptr<vector<string>> file;
};
TextQuery.cpp
#include"TextQuery.h"
#include<sstream>
#include<algorithm>
#include<iostream>
TextQuery::TextQuery(ifstream& is) : file(new vector<string>)
{
string text;
while (getline(is, text))
{
file->push_back(text);
int n = file->size() - 1;
istringstream line(text);
string word;
while (line >> word)
{
shared_ptr<set<line_no>>& lines = wm[word]; //lines是指向set的智能指针
if (!lines) //第一次遇到word时需要给lines分配一个新的内存空间
lines.reset(new set<line_no>);
lines->insert(n);
}
}
}
QueryResult TextQuery::query(const string& sought) const
{
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(sought);
if (loc == wm.end())
return QueryResult(sought, nodata, file); //未找到
else
return QueryResult(sought, loc->second, file);
}
ostream& print(ostream& os, const QueryResult& qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " " << ((qr.lines->size()) > 1 ? "times" : "time") << endl;
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
return os;
}
Homework
Test 12.2
#include<vector>
#include<string>
#include<memory>
#include<initializer_list>
using std::vector, std::string, std::initializer_list, std::shared_ptr, std::make_shared;
class strblob
{
public:
typedef vector<string>::size_type size_type;
strblob() : data(make_shared<vector<string>>()) {};
strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
bool empty() const { return data->empty(); }
//添加和删除元素
void push_back(const string& t) { data->push_back(t); };
void pop_back();
//元素访问
string& front();
const string& front() const;
string& back();
const string& back() const;
private:
//strblob类的底层是一个vector<string>
shared_ptr<vector<string>> data;
//如果data[i]不合法,抛出一个异常
void check(size_type i, const string& msg) const;
};
#include "strblob.h"
#include<stdexcept>
using std::out_of_range;
void strblob::check(size_type i, const string& msg) const
{
if (i >= data->size())
throw out_of_range(msg); //throw索引越界的异常
}
//访问元素
string& strblob::front()
{
check(0, "front on empty strblob");
return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
check(0, "front on empty strblob");
return data->front();
}
string& strblob::back()
{
check(0, "front on empty strblob");
return data->back();
}
const string& strblob::back() const
{
check(0, "front on empty strblob");
return data->back();
}
//删除元素
void strblob::pop_back()
{
check(0, "pop_back on empty strblob");
return data->pop_back();
}
Test 12.5
explicit阻止了参数传递时的隐式类型转换,这意味着我们不能直接用{"s1", "s2"}
类似的列表作为形参传递给构造函数。通常来说,使用隐式类型转换可以让程序写起来更加简单方便给。
但这种隐式转换并不总是好的。例如,列表中可能并非都是合法的值。再如,对于接受 strblob的函数,传递给它一个列表,会创建一个临时的 strblob 对象,用列表对其初始化,然后将其传递给函数,当函数完成后,此对象将被丢弃,再也无法访问了。对于这些情况,我们可以定义显式的构造函数,禁止隐式类类型转换。
Test 12.6
vector<int>* func()
{
return new vector<int>({ 1, 2, 3, 4 , 5 });
}
vector<int> save(vector<int>* vp)
{
vector<int> ivec = *vp;
delete vp;
return ivec;
}
void print(const vector<int>& ivec)
{
for (auto& i : ivec)
cout << i << " ";
}
int main()
{
print(save(func()));
return 0;
}
Test 12.7
shared_ptr<vector<int>> func()
{
return make_shared<vector<int>>(10, 1);
}
vector<int> save(shared_ptr<vector<int>> sp)
{
return *sp;
}
void print(const vector<int>& ivec)
{
for (auto& i : ivec)
cout << i << " ";
}
int main()
{
print(save(func()));
return 0;
}
Test 12.8
从程序片段看,可以猜测程序员的意图是通过 new 返回的指针值来区分内存分配成功或失败 —— 成功返回一个合法指针,转换为整型是一个非零值,可转换为 bool 值 true;分配失败,p 得到 nullptr,其整型值是 0,可转换为 bool 值 false。
但普通 new 调用在分配失败时抛出一个异常 bad_alloc,而不是返回 nullptr,因此程序不能达到预想的目的。
可将 new int
改为 new (nothrow) int
来令 new 在分配失败时不抛出异常,而是返回 nullptr。但这仍然不是一个好方法,应该通过捕获异常或是判断返回的指针来返回 true 或 false,而不是依赖类型转换。
Test 12.10
此调用是正确的,利用 p 创建一个临时的 shared_ptr 赋予 process 的参数 ptr,p 和 ptr 都指向相同的 int 对象,引用计数被正确地置为 2。process 执行完毕后,ptr 被销毁,int 对象 42 引用计数减 1,这是正确的 —— 只有 p 指向它。
Test 12.14
struct connection
{
};
struct destination;
connection connect(destination*);
void disconnect(connection);
void end_connection(connection* p) { disconnect(*p); }
void f(destination& d)
{
connection c = connect(&d);
shared_ptr<connection> p(&c, end_connection);
//....
}
Test 12.15
struct connection
{
};
struct destination;
connection connect(destination*);
void disconnect(connection);
void f(destination& d)
{
connection c = connect(&d);
shared_ptr<connection> p(&c, [](connection *p) {disconnect(*p);});
//....
}
Test 12.19
strblob.h
#include<initializer_list>
#include<string>
#include<memory>
#include<vector>
using namespace std;
class strblobptr; //先声明类
class strblob
{
friend class strblobptr;
public:
typedef vector<string>::size_type size_type;
strblob() : data(make_shared<vector<string>>()) {};
strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
bool empty() const { return data->empty(); }
//添加和删除元素
void push_back(const string& t) { data->push_back(t); };
void pop_back();
//元素访问
string& front();
const string& front() const;
string& back();
const string& back() const;
//迭代器操作
strblobptr begin();
strblobptr end();
private:
//strblob类的底层是一个vector<string>
shared_ptr<vector<string>> data;
//如果data[i]不合法,抛出一个异常
void check(size_type i, const string& msg) const;
};
class strblobptr
{
public:
strblobptr() : curr(0) {};
strblobptr(strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
string& deref() const; //访问指针所指元素
strblobptr& incr(); //递增指针
private:
shared_ptr<vector<string>> check(size_t, const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
strblob.cpp
#include "strblob.h"
#include<stdexcept>
shared_ptr<vector<string>> strblobptr::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& strblobptr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
strblobptr& strblobptr::incr()
{
check(curr, "increment past end of strblobptr");
++curr;
return *this;
}
void strblob::check(size_type i, const string& msg) const
{
if (i >= data->size())
throw out_of_range(msg); //throw索引越界的异常
}
//访问元素
string& strblob::front()
{
check(0, "front on empty strblob");
return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
check(0, "front on empty strblob");
return data->front();
}
string& strblob::back()
{
check(0, "front on empty strblob");
return data->back();
}
const string& strblob::back() const
{
check(0, "front on empty strblob");
return data->back();
}
//删除元素
void strblob::pop_back()
{
check(0, "pop_back on empty strblob");
return data->pop_back();
}
//迭代器操作
strblobptr strblob::begin()
{
return strblobptr(*this);
}
strblobptr strblob::end()
{
auto ret = strblobptr(*this, data->size());
return ret;
}
Test 12.20
strblob.h
#include<initializer_list>
#include<string>
#include<memory>
#include<vector>
using namespace std;
class strblobptr; //先声明类
class strblob
{
friend class strblobptr;
public:
typedef vector<string>::size_type size_type;
strblob() : data(make_shared<vector<string>>()) {};
strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
bool empty() const { return data->empty(); }
//添加和删除元素
void push_back(const string& t) { data->push_back(t); };
void pop_back();
//元素访问
string& front();
const string& front() const;
string& back();
const string& back() const;
//迭代器操作
strblobptr begin();
strblobptr end();
private:
//strblob类的底层是一个vector<string>
shared_ptr<vector<string>> data;
//如果data[i]不合法,抛出一个异常
void check(size_type i, const string& msg) const;
};
class strblobptr
{
friend bool eq(const strblobptr& lhs, const strblobptr& rhs);
friend bool neq(const strblobptr& lhs, const strblobptr& rhs);
public:
strblobptr() : curr(0) {};
strblobptr(strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
string& deref() const; //访问指针所指元素
strblobptr& incr(); //递增指针
private:
shared_ptr<vector<string>> check(size_t, const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
bool eq(const strblobptr& lhs, const strblobptr& rhs);
bool neq(const strblobptr& lhs, const strblobptr& rhs);
strblob.cpp
#include "strblob.h"
#include<stdexcept>
shared_ptr<vector<string>> strblobptr::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& strblobptr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
strblobptr& strblobptr::incr()
{
check(curr, "increment past end of strblobptr");
++curr;
return *this;
}
void strblob::check(size_type i, const string& msg) const
{
if (i >= data->size())
throw out_of_range(msg); //throw索引越界的异常
}
//访问元素
string& strblob::front()
{
check(0, "front on empty strblob");
return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
check(0, "front on empty strblob");
return data->front();
}
string& strblob::back()
{
check(0, "front on empty strblob");
return data->back();
}
const string& strblob::back() const
{
check(0, "front on empty strblob");
return data->back();
}
//删除元素
void strblob::pop_back()
{
check(0, "pop_back on empty strblob");
return data->pop_back();
}
//迭代器操作
strblobptr strblob::begin()
{
return strblobptr(*this);
}
strblobptr strblob::end()
{
auto ret = strblobptr(*this, data->size());
return ret;
}
// StrBlobPtr 的比较操作
bool eq(const strblobptr& lhs, const strblobptr& rhs) {
auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
// 若底层的 vector 是同一个
if (l == r)
// 则两个指针都是空,或者指向相同元素时,它们相等
return (!r || lhs.curr == rhs.curr);
else
return false; // 若指向不同 vector,则不可能相等
}
bool neq(const strblobptr& lhs, const strblobptr& rhs) {
return !eq(lhs, rhs);
}
main.cpp
int main()
{
fstream fin("infile.txt");
string line;
strblob strb;
while (getline(fin, line))
{
strb.push_back(line);
}
for (strblobptr sbp(strb, 0); neq(sbp, strb.end()); sbp.incr())
cout << sbp.deref() << endl;
return 0;
}
Test 12.22
strblob.h
class conststrblobptr
{
public:
conststrblobptr() : curr(0) {};
conststrblobptr(const strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
string& deref() const; //访问指针所指元素
conststrblobptr& incr(); //递增指针
private:
shared_ptr<vector<string>> check(size_t, const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
strblob.cpp
shared_ptr<vector<string>> conststrblobptr::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& conststrblobptr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
conststrblobptr& conststrblobptr::incr()
{
check(curr, "increment past end of strblobptr");
++curr;
return *this;
}
Test 12.23
int main()
{
const char* cc1 = "hello ";
const char* cc2 = "world";
unsigned len = strlen(cc1) + strlen(cc2) + 1;
char* cp = new char[len]();
strcat_s(cp, len, cc1);
strcat_s(cp, len, cc2);
for (int i = 0; i < 10; ++i)
cout << *cp++ << " ";
delete[] cp;
string str1{ "hello " };
string str2{ "world" };
unsigned slen = str1.size() + str2.size() + 1;
char* sp = new char[slen]();
strcat_s(sp, slen, (str1 + str2).c_str());
for (int i = 0; i < 10; ++i)
cout << *sp++ << " ";
delete[] sp;
return 0;
}
Test 12.24
int main()
{
size_t len = 5;
char* r = new char[len + 1]();
cin.get(r, len + 1);
cout << r ;
// 释放动态数组
delete[] r;
return 0;
}
使用cin.get()函数,只读取前len+1个字符
Test 12.26
int main()
{
size_t n = 20;
allocator<string> alloc;
auto const p = alloc.allocate(n); //分配n个未初始化的string,p永远指向首元素
auto q = p; //q指向首元素
fstream fin("infile.txt");
string str;
while (fin >> str && q != p + n)
alloc.construct(q++, str); //设置alloc中的元素,并让指针q递增直到alloc末元素的下一位置
const size_t size = q - p; //表示我们读取了多少个元素
cout << size;
//销毁alloc中的元素并释放内存
while (q != p)
alloc.destroy(--q);
alloc.deallocate(p, n);
return 0;
}
Test 12.27 自定义TextQuery类
这里是自己实现的文件单词查询功能类,可以和书中的类进行比较,学习别人的优点
TextQuery.h
#include<vector>
#include<string>
#include<set>
#include<map>
#include<fstream>
class TextQuery
{
friend class QueryResult;
public:
TextQuery();
TextQuery(fstream& fin);
void QueryWord(const string& word);
private:
vector<string> fileline;
map<string, set<int>> occurrow;
};
TextQuery…cpp
#include"TextQuery.h"
#include<sstream>
#include<algorithm>
#include<iostream>
TextQuery::TextQuery(fstream& fin)
{
string line, word;
int row = 1;
while (getline(fin, line))
{
fileline.push_back(line);
istringstream strin(line);
//把单词和行号添加进map
while (strin >> word)
occurrow[word].insert(row);
++row;
}
}
void TextQuery::QueryWord(const string& word)
{
if (occurrow.find(word) == occurrow.end())
cout << "no word in file" << endl;
else
{
cout << "element occur " << occurrow[word].size() << "times" << endl;
for (auto& row : occurrow[word])
{
cout << "(line " << row << ") " << fileline[row - 1] << endl;
}
}
}
main.cpp
#include"TextQuery.h"
int main()
{
fstream fin("infile.txt");
TextQuery dict(fin);
dict.QueryWord("you're");
return 0;
}