目录
12.1.1 shared_ptr类(12.1 ~ 12.5)
12.1.3 shared_ptr和new结合使用(12.10 ~ 12.13)
12.1.5 unique_ptr(12.16 ~ 12.18)
12.1.6 weak_ptr(12.19 ~ 12.22)
12.3.1 文本查询程序设计(12.27 ~ 12.29)
12.3.2 文本查询程序类的定义(12.30 ~ 12.33)
工作的间隙看的,所以输出比较慢,希望能巩固基础,再往后深入。
一直有参考这位同学的blog的答案:C++Primer第五版——习题答案+详解(完整版)_MISAYAONE的博客-CSDN博客,不过好像这位同学看的很快有很一些些不是很正确,看评论也有都一一修正(收费了,又找了这个:安月月 - 博客园,又顺藤摸瓜找到了这个:GitHub - Mooophy/Cpp-Primer: C++ Primer 5 answers,YYDS~)。
这个答案也是自己看书然后输出的,也可能有问题,如果有发现什么问题,欢迎评论一起讨论!!
默认大家都有了第5版的纸质书或电子书,这里就只记录题号和答案(其实对原书的截图有点侵犯版权的感觉,狗头保命)
12.1:
b1和b2都包含4个元素。
12.2:
- string& StrBlob::front() const {
- check(0, "front on empty StrBlob");
- return data->front();
- }
-
- string& StrBlob::back() const {
- check(0, "back on empty StrBlob");
- return data->back();
- }
12.3:
不需要,因为这两个函数都不会对参数进行修改。
12.4:
因为data_size类型是size_type,是一个无符号类型,即使是负数,也会自动转化为非负。
12.5:
explicit的作用就是抑制构造函数的隐式转换。
优点:不会自动的进行类型转换,必须清楚的知道类类型。
缺点:必须用构造函数显示创建一个对象,不够方便简单。
12.6:
- void Input(vector<int>* ivec){
- if(!ivec) return;
- string s;
- while(cin >> s){
- stringstream a(s);
- int i;
- a >> i;
- ivec->push_back(i);
- }
- }
-
- void Output(vector<int>* ivec) {
- if(!ivec) return;
- for(const auto& i : *ivec){
- cout << i << " ";
- }
- cout << endl;
- }
-
- int main() {
- auto ivec = IntVectorPointerFactory();
- Input(ivec);
- Output(ivec);
- delete ivec;
- ivec = nullptr;
- }
- // 1 1 1 sdf
- // ^Z
- // 1 1 1 0
12.7:
- shared_ptr
int>> IntVectorPointerFactory(){ - return make_shared
int>>(); - }
-
- void Input(const shared_ptr
int >>& ivec){ - if(!ivec) return;
- string s;
- while(cin >> s){
- stringstream a(s);
- int i;
- a >> i;
- ivec->push_back(i);
- }
- }
-
- void Output(const shared_ptr
int >>& ivec) { - if(!ivec) return;
- for(const auto& i : *ivec){
- cout << i << " ";
- }
- cout << endl;
- }
-
- int main() {
- auto ivec = IntVectorPointerFactory();
- Input(ivec);
- Output(ivec);
- }
- // 1 1 1 sdf
- // ^Z
- // 1 1 1 0
12.8:
p的类型是int*,函数返回值却是bool型。(错误答案)
p是一个内置类型的指针,返回p会使得p的类型转化为bool类型,其指向的动态内存空间将无法得到释放。
12.9:
r = q,r指向q指向的内存地址,r原指向的内存未发生任何改变;(补充:r原来指向的内存空间将得不到释放,造成内存泄漏)
r2 = q2,q2智能指针的引用计数加一,r2智能指针的引用计数减一,原指针指向的内存释放,现r2指针指向q2。
12.10:
正确的,shared_ptr
12.11:
process调用结束后,指针析构,p被销毁,p指向的内存被释放了,再使用p就是未定义。
12.12:
(a) 合法,复制sp引用计数+1,调用完引用计数-1,不影响原sp的使用。
(b) 不合法,不能传递内置指针给shared_ptr,无法隐式转换。
(c) 不合法,与(b)同样的原因,不能传递内置指针给shared_ptr,无法隐式转换。
(d) 合法,但process调用完后不能再使用p,因为p指向的内存被释放。
12.13:
抄的答案:删除p之后,会导致p指向的内存被释放,此时sp就会变成空悬指针,在sp指针被销毁时,该块内存会被二次delete,执行后产生错误:double free
12.14:
没有想到其他写法。
12.15:
- void f(destination &d /* 其他参数 */) {
- connection c = connect(&d);
- shared_ptr
p(&c , [](connection *p){ - disconnect(*p);
- });
- }
12.16:
- unique_ptr<int> p1(new int(10));
- unique_ptr<int> p2(p1);
- // unique_ptr
p2 = p1;
error: use of deleted function 'std::unique_ptr<Tp, _Dp>::unique_ptr(const std::unique_ptr<Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete
以下网上答案,没理解
error C2248: “std::unique_ptr<Ty>::unique_ptr”: 无法访问 private 成员(在“std::unique_ptr<Ty>”类中声明)
12.17:
(a)不合法,不能用对象初始化unique_ptr;
(b)合法,pi野指针;
(c)合法,pi2野指针;
(d)合法,ix对象被清空;
(e)合法;
(f)不合法,一块内存对象只能被一个unique_ptr持有。
和网络答案不一致,但也没有很理解,以上为个人理解,欢迎指正。
12.18:
shared_ptr指向的对象可以同时被多个shared_ptr持有,release会将指针置为空,导致其他持有这个指针的shared_ptr对象失效。
12.19:
- // 这里的代码主要有两个问题
- // 1.循环引用 可以在类中声明 在StrBlobPtr后再定义begin end
- // 2.需要额外给StrBlobPtr类添加pos函数来比较
- class StrBlobPtr;
- class StrBlob {
- public:
- typedef std::vector
::size_type size_type; - friend class StrBlobPtr;
- StrBlob();
- StrBlob(std::initializer_list
il); - size_type size() const { return data->size(); }
- bool empty() const { return data->empty(); }
- void push_back(const std::string& t) { data->push_back(t); }
- void pop_back();
- std::string& front();
- std::string& back();
- StrBlobPtr begin();
- StrBlobPtr end();
- private:
- std::shared_ptr
> data; - void check(size_type i, const std::string& msg) const;
- };
-
- StrBlob::StrBlob() : data(make_shared
>()) { -
- }
-
- StrBlob::StrBlob(initializer_list
il) : data(make_shared>(il)) { -
- }
-
- 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();
- }
-
- void StrBlob::check(size_type i, const string& msg) const {
- if(i >= data->size()) {
- throw out_of_range(msg);
- }
- }
-
- class StrBlobPtr {
- public:
- StrBlobPtr() : curr(0) { }
- StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
- std::string& deref() const;
- StrBlobPtr& incr();
- size_t pos() const;
- private:
- std::shared_ptr
> check(std::size_t, const std::string&) const; - std::weak_ptr
> wptr; - std::size_t curr;
- };
-
- std::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;
- }
-
- std::shared_ptr
> StrBlobPtr::check(std::size_t i, const std::string &msg) const { - auto ret = wptr.lock();
- if(!ret)
- throw std::runtime_error("unbound StrBlobPtr");
- if(i >= ret->size())
- throw std::out_of_range(msg);
- return ret;
- }
-
- size_t StrBlobPtr::pos() const {
- return curr;
- }
-
- StrBlobPtr StrBlob::begin() {
- return StrBlobPtr(*this);
- }
-
- StrBlobPtr StrBlob::end() {
- auto ret = StrBlobPtr(*this, data->size());
- return ret;
- }
12.20:
- int main() {
- std::string str{};
- StrBlob str_blob{};
- while(cin >> str) {
- str_blob.push_back(str);
- }
- for (StrBlobPtr pbeg(str_blob.begin()), pend(str_blob.end()); pbeg.pos() != pend.pos(); pbeg.incr()) {
- cout << pbeg.deref() << std::endl;
- }
- }
12.21:
将合法性检查与元素获取的返回语句分离开来,代码更清晰易读。
12.22:
StrBlobPtr(const StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
12.23:
- // dynamically allocated array of char
- char *concatenate_string = new char[strlen("hello " "world") + 1]();
- strcat(concatenate_string, "hello ");
- strcat(concatenate_string, "world");
- std::cout << concatenate_string << std::endl;
- delete [] concatenate_string;
-
- // std::string
- std::string str1{ "hello " }, str2{ "world" };
- std::cout << str1 + str2 << std::endl;
-
- // hello world
- // hello world
- // copy from https://github.com/Mooophy/Cpp-Primer/blob/master/ch12/ex12_23.cpp
12.24:
- string str;
- cin >> str;
- char *input = new char[str.size() + 1]();
- strcat(input, str.c_str());
- cout << input << endl;
- delete [] input;
- // input: helloworld
- // output: helloworld
12.25:
delete [] pa;
12.26:
- allocator
alloc; // 可以分配string的allocator对象 - auto const p = alloc.allocate(n); // 分配n个未初始化的string
- string s;
- auto q = p;
- while(cin >> s && q != p + n)
- alloc.construct(q++, s);
-
- // 输出 & 析构
- while(q != p) {
- cout << *--q << endl;
- alloc.destroy(q);
- }
-
- // 释放内存
- alloc.deallocate(p, n);
12.27:
- class TextQuery{
- public:
- TextQuery(ifstream &infile);
- void query(string s);
-
- private:
- vector
line_text_{}; - map
size_t>> word_lines_{}; - };
-
- TextQuery::TextQuery(ifstream &infile){
- string line_string;
- size_t line = 1;
- while(getline(infile, line_string)){
- cout << line_string << endl;
- line_text_.push_back(line_string);
- istringstream stream(line_string);
- string word;
- while(stream >> word){
- auto iter = word_lines_.find(word);
- set<size_t> lines{};
- if(iter != word_lines_.end()) {
- lines = iter->second;
- }
- lines.insert(line);
- word_lines_[word] = lines;
- }
- line++;
- }
- }
-
- void TextQuery::query(string s) {
- auto iter = word_lines_.find(s);
- if(iter != word_lines_.end()){
- auto lines = iter->second;
- cout << s << " occurs " << lines.size() << " times" << endl;
- for(const auto index : lines) {
- if(index >= 1 && index <= line_text_.size()){
- cout << "(line "<< index << ") " << line_text_[index - 1] << endl;
- }
- }
- }
-
- }
-
- void runQueries(ifstream &infile) {
- // infile 是一个ifstream,指向我们要处理的文件
- TextQuery tq(infile); // 保存文件并建立查询map
- // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
- while(true) {
- cout << "enter word to look for, or q to quit: ";
- string s;
- // 若遇到文件尾或用户输入了'q'时循环终止
- if(!(cin >> s) || s == "q") break;
- // 指向查询并打印结果
- //print(cout, tq.query(s)) << endl;
- tq.query(s);
- }
- }
-
- int main() {
- ifstream fstrm1("1.txt");
- runQueries(fstrm1);
- }
-
- // 自己写的 有点简单 只用了一个类 也没有用到智能指针
- // 输入是文件1.txt 会打印出输入的内容
- /*
- brb be right back
- k okay?
- y why
- r are
- u you
- pic picture
- thk thanks~
- 18r later
- k okay!
- enter word to look for, or q to quit: k
- k occurs 2 times
- (line 2) k okay?
- (line 9) k okay!
- enter word to look for, or q to quit: r
- r occurs 1 times
- (line 4) r are
- enter word to look for, or q to quit: q
- */
- // https://github.com/Mooophy/Cpp-Primer/tree/master/ch12 移除了输入中的标点符号
12.28:
- int main() {
- ifstream fstrm1("1.txt");
-
- vector
line_text{}; - map
size_t>> word_lines{}; -
- string line_string;
- size_t line = 1;
- while(getline(fstrm1, line_string)){
- cout << line_string << endl;
- line_text.push_back(line_string);
- istringstream stream(line_string);
- string word;
- while(stream >> word){
- auto iter = word_lines.find(word);
- set<size_t> lines{};
- if(iter != word_lines.end()) {
- lines = iter->second;
- }
- lines.insert(line);
- word_lines[word] = lines;
- }
- line++;
- }
-
- while(true) {
- cout << "enter word to look for, or q to quit: ";
- string s;
- // 若遇到文件尾或用户输入了'q'时循环终止
- if(!(cin >> s) || s == "q") break;
- // 指向查询并打印结果
- //print(cout, tq.query(s)) << endl;
- auto iter = word_lines.find(s);
- if(iter != word_lines.end()){
- auto lines = iter->second;
- cout << s << " occurs " << lines.size() << " times" << endl;
- for(const auto index : lines) {
- if(index >= 1 && index <= line_text.size()){
- cout << "(line "<< index << ") " << line_text[index - 1] << endl;
- }
- }
- }
- }
- }
-
- // 输出与上面一致
12.29:
- void runQueries(ifstream &infile) {
- // infile 是一个ifstream,指向我们要处理的文件
- TextQuery tq(infile); // 保存文件并建立查询map
- // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
-
- do{
- cout << "enter word to look for, or q to quit: ";
- string s;
- // 若遇到文件尾或用户输入了'q'时循环终止
- if(!(cin >> s) || s == "q") break;
- // 指向查询并打印结果
- //print(cout, tq.query(s)) << endl;
- tq.query(s);
- }
- while(true);
- }
-
- // 倾向于直接用while,清晰
- // https://www.cnblogs.com/songshuguiyu/p/9598196.html 这里写do while更简洁…
12.30:
- class QueryResult; // 为了定义函数query的返回类型
- class TextQuery {
- public:
- using line_no = std::vector
::size_type; - TextQuery(std::ifstream&);
- QueryResult query(const std::string&) const;
- private:
- std::shared_ptr
> file; // 输入文件 - // 每个单词到它所在的行号的集合的映射
- std::map
>> wm; - };
-
- TextQuery::TextQuery(ifstream &is) : file(new vector
) { - string text;
- while(getline(is, text)) { // 对文件中每一行
- file->push_back(text); // 保存此行文本
- int n = file->size() - 1; // 当前行号
- istringstream line(text); // 将行文本分解为单词
- string word;
- while(line >> word) { // 对行中每个单词
- // 如果单词不在wm中,以之为下标在wm中添加一项
- auto &lines = wm[word]; // lines是shared_ptr(如果lines为空没有使用引用是会失败的)
- if(!lines) // 在第一次遇到此单词时,此指针为空
- lines.reset(new set
); // 分配一个新的set - lines->insert(n); // 将此行号插入set中
- }
- }
- }
-
- class QueryResult {
- friend std::ostream& print(std::ostream&, const QueryResult&); // 友元函数不需要放在public或private里吗?
- public:
- QueryResult(std::string s, std::shared_ptr
> p, std::shared_ptr> f) : sought(s), lines(p), file(f) { } - private:
- std::string sought; // 查询单词
- std::shared_ptr
> lines; // 出现的行号 - std::shared_ptr
> file; // 输入文字 - };
-
- QueryResult TextQuery::query(const string & sought) const {
- // 如果未找到sought,将返回指向此set的指针
- static shared_ptr
> nodata(new set); - // 使用find而不是下标运算符来查找单词,避免将单词添加到wm中!
- auto loc = wm.find(sought);
- if(loc == wm.end())
- return QueryResult(sought, nodata, file); // 未找到
- else
- return QueryResult(sought, loc->second, file);
- }
-
- void runQueries(ifstream &infile) {
- // infile 是一个ifstream,指向我们要处理的文件
- TextQuery tq(infile); // 保存文件并建立查询map
- // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
- while(true) {
- cout << "enter word to look for, or q to quit: ";
- string s;
- // 若遇到文件尾或用户输入了'q'时循环终止
- if(!(cin >> s) || s == "q") break;
- // 指向查询并打印结果
- print(cout, tq.query(s)) << endl;
- }
- }
-
- string make_plural(size_t ctr, const string &word, const string &ending) {
- return ctr > 1 ? word + ending : word;
- }
-
- ostream &print(ostream &os, const QueryResult &qr) {
- // 如果找到了单词,打印出现次数和所有出现的位置
- os << qr.sought << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "times", "s") << endl;
- // 打印单词出现的每一行
- for(auto num : *qr.lines) // 对set中每个单词
- // 避免行号从0开始给用户带来的困惑
- os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
- return os;
- }
-
- int main() {
- ifstream fstrm1("1.txt");
- runQueries(fstrm1);
- }
- // 12.27写过了,这里将书中的代码copy运行
12.31:
一行中有两个重复的单词,输出时,如果vector不过滤,会将这一行输出两遍,使用set不用过滤。
12.32:
- class StrBlobPtr;
-
- class StrBlob {
- public:
- typedef std::vector
::size_type size_type; - friend class StrBlobPtr;
- StrBlob();
- StrBlob(std::initializer_list
il); - size_type size() const { return data->size(); }
- bool empty() const { return data->empty(); }
- void push_back(const std::string& t) { data->push_back(t); }
- void pop_back();
- std::string& front();
- std::string& back();
- StrBlobPtr begin();
- StrBlobPtr end();
- private:
- std::shared_ptr
> data; - void check(size_type i, const std::string& msg) const;
- };
-
- StrBlob::StrBlob() : data(make_shared
>()) { -
- }
-
- StrBlob::StrBlob(initializer_list
il) : data(make_shared>(il)) { -
- }
-
- 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();
- }
-
- void StrBlob::check(size_type i, const string& msg) const {
- if(i >= data->size()) {
- throw out_of_range(msg);
- }
- }
-
- class StrBlobPtr {
- public:
- StrBlobPtr() : curr(0) { }
- StrBlobPtr(const StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
- std::string& deref() const;
- StrBlobPtr& incr();
- size_t pos() const;
- private:
- std::shared_ptr
> check(std::size_t, const std::string&) const; - std::weak_ptr
> wptr; - std::size_t curr;
- };
-
- std::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;
- }
-
- std::shared_ptr
> StrBlobPtr::check(std::size_t i, const std::string &msg) const { - auto ret = wptr.lock();
- if(!ret)
- throw std::runtime_error("unbound StrBlobPtr");
- if(i >= ret->size())
- throw std::out_of_range(msg);
- return ret;
- }
-
- size_t StrBlobPtr::pos() const {
- return curr;
- }
-
- StrBlobPtr StrBlob::begin() {
- return StrBlobPtr(*this);
- }
-
- StrBlobPtr StrBlob::end() {
- auto ret = StrBlobPtr(*this, data->size());
- return ret;
- }
-
- class QueryResult; // 为了定义函数query的返回类型
- class TextQuery {
- public:
- using line_no = std::vector
::size_type; - TextQuery(std::ifstream&);
- QueryResult query(const std::string&) const;
- private:
- std::shared_ptr
> file; // 输入文件 - std::shared_ptr
file2; - // 每个单词到它所在的行号的集合的映射
- std::map
>> wm; - };
-
- TextQuery::TextQuery(ifstream &is) : file2(make_shared
()) { - string text;
- while(getline(is, text)) { // 对文件中每一行
- file2->push_back(text); // 保存此行文本
- int n = file2->size() - 1; // 当前行号
- istringstream line(text); // 将行文本分解为单词
- string word;
- while(line >> word) { // 对行中每个单词
- // 如果单词不在wm中,以之为下标在wm中添加一项
- auto &lines = wm[word]; // lines是shared_ptr(如果lines为空没有使用引用是会失败的)
- if(!lines) // 在第一次遇到此单词时,此指针为空
- lines.reset(new set
); // 分配一个新的set - lines->insert(n); // 将此行号插入set中
- }
- }
- }
-
- class QueryResult {
- friend std::ostream& print(std::ostream&, const QueryResult&); // 友元函数不需要放在public或private里吗?
- public:
- QueryResult(std::string s, std::shared_ptr
> p, std::shared_ptr f) : sought(s), lines(p), file2(f) { } - private:
- std::string sought; // 查询单词
- std::shared_ptr
> lines; // 出现的行号 - std::shared_ptr
> file; // 输入文字 - std::shared_ptr
file2; // 输入文字 - };
-
- QueryResult TextQuery::query(const string & sought) const {
- // 如果未找到sought,将返回指向此set的指针
- static shared_ptr
> nodata(new set); - // 使用find而不是下标运算符来查找单词,避免将单词添加到wm中!
- auto loc = wm.find(sought);
- if(loc == wm.end())
- return QueryResult(sought, nodata, file2); // 未找到
- else
- return QueryResult(sought, loc->second, file2);
- }
-
- void runQueries(ifstream &infile) {
- // infile 是一个ifstream,指向我们要处理的文件
- TextQuery tq(infile); // 保存文件并建立查询map
- // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
- while(true) {
- cout << "enter word to look for, or q to quit: ";
- string s;
- // 若遇到文件尾或用户输入了'q'时循环终止
- if(!(cin >> s) || s == "q") break;
- // 指向查询并打印结果
- print(cout, tq.query(s)) << endl;
- }
- }
-
- string make_plural(size_t ctr, const string &word, const string &ending) {
- return ctr > 1 ? word + ending : word;
- }
-
- ostream &print(ostream &os, const QueryResult &qr) {
- // 如果找到了单词,打印出现次数和所有出现的位置
- os << qr.sought << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "times", "s") << endl;
- // 打印单词出现的每一行
- for(auto num : *qr.lines) { // 对set中每个单词
- // 避免行号从0开始给用户带来的困惑
- StrBlobPtr p(*qr.file2, num);
- os << "\t(line " << num + 1 << ") " << p.deref() << endl;
- }
- return os;
- }
-
- int main() {
- ifstream fstrm1("1.txt");
- runQueries(fstrm1);
- }
- // 将之前的StrBlob和StrBlobPtr也放过来了
- // 里面有一些上题无用的变量file没有删哇~
12.33:
- class QueryResult {
- using ResultIter = std::set
::iterator; - friend std::ostream& print(std::ostream&, const QueryResult&); // 友元函数不需要放在public或private里吗?
- public:
- QueryResult(std::string s, std::shared_ptr
> p, std::shared_ptr f) : sought(s), lines(p), file2(f) { } - ResultIter begin() const { return nos->begin(); }
- ResultIter end() const { return nos->end(); }
- shared_ptr
get_file() const { return file2; } - private:
- std::string sought; // 查询单词
- std::shared_ptr
> lines; // 出现的行号 - std::shared_ptr
> file; // 输入文字 - std::shared_ptr
file2; // 输入文字 - shared_ptr
> nos; - };
- // copy了一下这里的https://github.com/Mooophy/Cpp-Primer/blob/master/ch12/ex12_33.h