C++ Primer课后习题解答(第十二章)
Exercises Section 12.1.1
Ex12.1
// b1 和 b2 共享数据,故而 b1 和 b2 都有 4 个元素
StrBlob b1;
{
Strblob b2 = {"a", "an", "the"};
b1 = b2;
b2.push_back("about");
}
Ex12.2
class StrBlob
{
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<std::string> il);
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
// add and remove elements
void push_back(const std::string &t) { data->push_back(t); }
void pop_back();
// element access
std::string &front();
std::string &back();
private:
std::shared_ptr<std::vector<std::string>> data;
// throws msg if data[i] isn't valid
void check(size_type i, const std::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()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
Ex12.3
不需要;push_back 和 pop-back 会改变元素数量,故而不能定义 const 版本
Ex12.4
完全OK;size_type 类型为 unsigned 类型
Ex12.5
explicit 使构造函数显式化,优点是排除了隐式转换带来的一系列错误问题,缺点是降低了程序的灵活性。
Exercises Section 12.1.2
Ex12.6
#include<iostream>
#include<vector>
#include<memory>
using namespace std;
vector<int> *fac()
{
return new vector<int>();
}
void add_element(vector<int> *fac)
{
int i = 0;
while (std::cin >> i)
fac->push_back(i);
}
void print_element(vector<int> *fac)
{
for (const auto &i: *fac)
std::cout << i << " ";
std::cout << endl;
}
int main()
{
auto pv = fac();
cout << "input some numbers: ";
add_element(pv);
print_element(pv);
delete pv;
system("pause");
return 0;
}
Ex12.7
#include<iostream>
#include<vector>
#include<memory>
using namespace std;
shared_ptr<vector<int>> fac()
{
return make_shared<vector<int>>();
}
void add_element(shared_ptr<vector<int>> fac)
{
int i = 0;
while (std::cin >> i)
fac->push_back(i);
}
void print_element(shared_ptr<vector<int>> fac)
{
for (const auto &i: *fac)
std::cout << i << " ";
std::cout << endl;
}
int main()
{
auto pv = fac();
cout << "input some numbers: ";
add_element(pv);
print_element(pv);
system("pause");
return 0;
}
Ex12.8
bool b()
{
int *p = new int; // 如果 new 失败,那么抛出 std::bad_alloc 异常
// 修改代码:int *p = new (nothrow) int;
// ...
return p;
}
Ex12.9
// q 和 r 使用 new 方法,如果内存未及时释放,会造成内存泄漏
int *q = new int(42), *r = new int(100);
r = q;
// q2 和 r2 使用智能指针,当把 q2 的值赋给 r2 时,q2 的引用计数增 1 而 r2 的引用计数减 1 变为 0,自动释放内存
auto q2 = make_shared<int>(42), r2 = make_shared<int>(100);
r2 = q2;
Exercises Section 12.1.3
Ex12.10
// 正确
shared_ptr<int> p(new int(42));
proces(shared_ptr<int>(p));
Ex12.11
// get函数会得到一个内置指针,指向动态指针 p 管理的对象;将其作为参数传入 process 函数中则有两个独立的动态指针指向同一个对象;
// 当 process 结束后, p 指针的内存也释放了
process(shared_ptr<int>(p.get()));
Ex12.12
auto p = new int();
auto sp = make_shared<int>();
a) process(sp); // 合法;将智能指针 sp 副本传入 process 函数中
b) process(new int()); // 不合法;普通指针不能隐式转换为智能指针
c) process(p); // 不合法;与 b 一样
d) process(shared_ptr(int)(p)); // 合法;将普通指针显式转换为智能指针,然后将智能指针副本传入 process
Ex12.13
// delete 只和 new 需要成对出现,不能用 delete 去释放 shared_ptr 内存,故而此代码会发生错误
auto sp = make_shared<int>();
auto p = sp.get();
delete p;
Exercises Section 12.1.4
Ex12.14
struct destination;
struct connection;
connection connnect(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);
}
Ex12.15
struct destination;
struct connection;
connection connnect(destination*);
void disconnect(connection);
void end_connection(connection *p) { disconnect(*p); }
void f(destination &d)
{
connection c = connect(&d);
shared_ptr<connection> p(&c, [](connection *p) { disconnect(*p); });
}
Exercises Section 12.1.5
Ex12.16
Ex12.17
int ix = 1024, *pi = &ix, *pi2 = new int(2048);
typedef unique_ptr<int> IntP;
a) IntP p0(ix); // 非法;类型不匹配
b) IntP p1(pi); // 合法
c) IntP p2(pi2); // 合法
d) IntP p3(&ix); // 合法
e) IntP p4(new int(2048)); // 合法
f) IntP p5(p2.get()); // 合法
Ex12.18
因为可能同时有多个 shared_ptr 指向同一个对象,共享对象所有权故而不需要 release。
Exercises Section 12.3.1
Ex12.27 28
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
using namespace std;
using line_no = vector<string>::size_type;
vector<string> file; // 文件以每行内容存储
map<string, set<line_no>> wm; // 单词到行号 set 的映射
string make_pluaral(size_t ctr, const string &word, const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
string cleanup_str(const string &word)
{
string ret;
for (auto it = word.begin(); it != word.end(); ++it)
{
if (!ispunct(*it))
ret += tolower(*it);
}
return ret;
}
void input_text(ifstream &is)
{
string text;
while (getline(is, text))
{
file.push_back(text); // 保留此行文本
int n = file.size() - 1; // 当前行号
istringstream line(text); // 将每行分解为每个单词
string word;
while (line >> word)
{
// 将当前行号插入到其行号 set 中
// 如果单词不在 wm 中,则添加一项
wm[cleanup_str(word)].insert(n);
}
}
}
ostream &query_and_print(const string &sought, ostream &os)
{
// 使用 find 而不是下标,避免将该单词添加到容器中
auto loc = wm.find(sought);
if (loc == wm.end()) // 未找到
{
os << sought << "occurs 0 time" << endl;
}
else
{
auto lines = loc->second; // 行号
os << sought << "occurs " << lines.size() << " times" << endl;
for (const auto &num : lines)
os << "\t(No " << num + 1 << "lines" << *(file.begin() + num) << endl;
}
return os;
}
void runQueries(ifstream &infile)
{
// infile指向我们要查询的文件
input_text(infile); // 读入文本并建立查询 map
while (true)
{
cout << "enter word to look for or enter \"q\" to quit: ";
string s;
if (!(cin >> s) || s == "q")
break;
query_and_print(s, cout) << endl;
}
}
int main(int argc, char *argv[])
{
ifstream infile;
if (argc < 2 || !(infile.open(argv[1], infile)))
{
cerr << "No input file !" << endl;
return EXIT_FAILURE;
}
runQueries(infile);
system("pause");
return 0;
}
Ex12.29
do
{
cout << "enter word to look for or enter \"q\" to quit: ";
string s;
if (!(cin >> s) || s == "q")
break;
query_and_print(s, cout) << endl;
} while (true);
使用 while 比使用 do_while 好
Exercises Section 12.3.2
Ex12.30
class QuertResult;
class TextQuery
{
public:
using line_no = std::vector<std::string>::size_type;
TextQuery(std::ifstream &);
QuertResult query(const std::string &) const;
private:
std::shared_ptr<std::vector<std::string>> file;
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
};
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)
{
auto &lines = wm[word];
if (!lines)
lines.reset(new set<line_no>);
lines->insert(n);
}
}
}
class QuertResult
{
friend std::ostream &print(std::ostream &, const QueryResult &);
public:
QuertResult(std::string s, std::share_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f) :
sought(s), lines(p), file(f) { }
private:
std::string sought;
std::shared_ptr<std::set<line_no>> lines;
std::shared_ptr<std::vector<std::string>> file;
};
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 QuertResult(sought, nodata, file);
else
return QuertResult(sought, loc->second, file);
}
ostream &print(ostream &os, const QuertResult &qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " "
<< make_pluar(qr.lines->size(), "time", "s") << endl;
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
return os;
}
Ex12.31
set 会维护关键字的顺序,vector不会;vector 插入元素的效率更高;由于不需要维护关键字的顺序,故而使用 vector 效率更高。
Ex12.32
class StrBlobPtr;
class QueryResult;
class StrBlob
{
friend class StrBlobPtr;
public:
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
bool empty() const { return data->empty(); }
size_type size() const { return data->size(); }
void push_back(const string &s) { data->push_back(s); }
void pop_back();
string& front();
const string& front() const;
string& back();
const string& back() const;
StrBlobPtr begin();
StrBlobPtr end();
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string &msg) const;
};
class StrBlobPtr
{
friend bool eq(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;
};
void StrBlob::check(size_type i, const string &msg) const
{
if (data->size() <= i)
throw out_of_range(msg);
}
StrBlob::StrBlob(): data(make_shared<vector<string>>()) { }
StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il)) { }
void StrBlob::pop_back()
{
check(0, "pop back on empty StrBlob");
data->pop_back();
}
string &StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
const string &StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
string &StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const string &StrBlob::back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
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;
}
inline bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
shared_ptr<vector<string>> l = lhs.wptr.lock(), r = rhs.wptr.lock();
if (l == r)
return (!r || lhs.curr == rhs.curr);
else
return false;
}
inline bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
return !eq(lhs, rhs);
}
class TextQuery
{
public:
using line_no = StrBlob::size_type;
TextQuery(ifstream&);
QueryResult query(const string&) const;
private:
shared_ptr<StrBlob> file;
map<string, shared_ptr<set<line_no>>> wm;
};
TextQuery::TextQuery(ifstream &infile): file(make_shared<StrBlob>())
{
string line;
string word;
line_no index = 0;
while (getline(infile, line)) {
file->push_back(line);
++index;
istringstream strline(line);
while (strline >> word) {
/* 消除词首和词尾的标点 */
if (ispunct(word[0]))
word.erase(0, 1);
if (ispunct(word[word.size()-1]))
word.pop_back();
if (ispunct(word[word.size()-1]))
word.pop_back();
if (!wm[word])
wm[word] = make_shared<set<line_no>>();
wm[word]->insert(index);
}
}
}
QueryResult TextQuery::query(const string &s) const
{
static shared_ptr<set<line_no>> nodata(make_shared<set<line_no>>());
auto loc = wm.find(s);
if (loc == wm.end())
return QueryResult(s, nodata, file);
else
return QueryResult(s, loc->second, file);
}
Ex12.33
// 添加如下成员函数
set<line_no>::const_iterator begin() const { return lines->begin(); }
set<line_no>::const_iterator end() const { return lines->end(); }
shared_ptr<StrBlob> get_file() { return file; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端