• C++ Primer第5版 习题答案 第十二章


    目录

    第十二章 动态内存

    12.1 动态内存与智能指针

    12.1.1 shared_ptr类(12.1 ~ 12.5)

    12.1.2 直接管理内存(12.6 ~ 12.9)

    12.1.3 shared_ptr和new结合使用(12.10 ~ 12.13)

    12.1.4 智能指针和异常(12.14 ~ 12.15)

    12.1.5 unique_ptr(12.16 ~ 12.18)

    12.1.6 weak_ptr(12.19 ~ 12.22)

    12.2 动态数组

    12.2.1 new和数组(12.23 ~ 12.25)

    12.2.2 allocator(12.26)

    12.3 使用标准库:文本查询程序

    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 动态内存与智能指针

    12.1.1 shared_ptr类(12.1 ~ 12.5)

    12.1:

    b1和b2都包含4个元素。

    12.2:

    1. string& StrBlob::front() const {
    2. check(0, "front on empty StrBlob");
    3. return data->front();
    4. }
    5. string& StrBlob::back() const {
    6. check(0, "back on empty StrBlob");
    7. return data->back();
    8. }

    12.3:

    不需要,因为这两个函数都不会对参数进行修改。

    12.4:

    因为data_size类型是size_type,是一个无符号类型,即使是负数,也会自动转化为非负。

    12.5:

    explicit的作用就是抑制构造函数的隐式转换。

    优点:不会自动的进行类型转换,必须清楚的知道类类型。

    缺点:必须用构造函数显示创建一个对象,不够方便简单。

    12.1.2 直接管理内存(12.6 ~ 12.9)

    12.6:

    1. void Input(vector<int>* ivec){
    2. if(!ivec) return;
    3. string s;
    4. while(cin >> s){
    5. stringstream a(s);
    6. int i;
    7. a >> i;
    8. ivec->push_back(i);
    9. }
    10. }
    11. void Output(vector<int>* ivec) {
    12. if(!ivec) return;
    13. for(const auto& i : *ivec){
    14. cout << i << " ";
    15. }
    16. cout << endl;
    17. }
    18. int main() {
    19. auto ivec = IntVectorPointerFactory();
    20. Input(ivec);
    21. Output(ivec);
    22. delete ivec;
    23. ivec = nullptr;
    24. }
    25. // 1 1 1 sdf
    26. // ^Z
    27. // 1 1 1 0

    12.7:

    1. shared_ptrint>> IntVectorPointerFactory(){
    2. return make_sharedint>>();
    3. }
    4. void Input(const shared_ptrint>>& ivec){
    5. if(!ivec) return;
    6. string s;
    7. while(cin >> s){
    8. stringstream a(s);
    9. int i;
    10. a >> i;
    11. ivec->push_back(i);
    12. }
    13. }
    14. void Output(const shared_ptrint>>& ivec) {
    15. if(!ivec) return;
    16. for(const auto& i : *ivec){
    17. cout << i << " ";
    18. }
    19. cout << endl;
    20. }
    21. int main() {
    22. auto ivec = IntVectorPointerFactory();
    23. Input(ivec);
    24. Output(ivec);
    25. }
    26. // 1 1 1 sdf
    27. // ^Z
    28. // 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.1.3 shared_ptr和new结合使用(12.10 ~ 12.13)

    12.10:

    正确的,shared_ptr p(new int(42)),引用计数+1,shared_ptr(p)引用计数+1,process调用后,引用计数减1,最后还剩1,可以正确使用。

    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.1.4 智能指针和异常(12.14 ~ 12.15)

    12.14:

    没有想到其他写法。

    12.15:

    1. void f(destination &d /* 其他参数 */) {
    2. connection c = connect(&d);
    3. shared_ptr p(&c , [](connection *p){
    4. disconnect(*p);
    5. });
    6. }

    12.1.5 unique_ptr(12.16 ~ 12.18)

    12.16:

    1. unique_ptr<int> p1(new int(10));
    2. unique_ptr<int> p2(p1);
    3. // 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.1.6 weak_ptr(12.19 ~ 12.22)

    12.19:

    1. // 这里的代码主要有两个问题
    2. // 1.循环引用 可以在类中声明 在StrBlobPtr后再定义begin end
    3. // 2.需要额外给StrBlobPtr类添加pos函数来比较
    4. class StrBlobPtr;
    5. class StrBlob {
    6. public:
    7. typedef std::vector::size_type size_type;
    8. friend class StrBlobPtr;
    9. StrBlob();
    10. StrBlob(std::initializer_list il);
    11. size_type size() const { return data->size(); }
    12. bool empty() const { return data->empty(); }
    13. void push_back(const std::string& t) { data->push_back(t); }
    14. void pop_back();
    15. std::string& front();
    16. std::string& back();
    17. StrBlobPtr begin();
    18. StrBlobPtr end();
    19. private:
    20. std::shared_ptr> data;
    21. void check(size_type i, const std::string& msg) const;
    22. };
    23. StrBlob::StrBlob() : data(make_shared>()) {
    24. }
    25. StrBlob::StrBlob(initializer_list il) : data(make_shared>(il)) {
    26. }
    27. string& StrBlob::front() {
    28. check(0, "front on empty StrBlob");
    29. return data->front();
    30. }
    31. string& StrBlob::back() {
    32. check(0, "back on empty StrBlob");
    33. return data->back();
    34. }
    35. void StrBlob::pop_back() {
    36. check(0, "pop_back on empty StrBlob");
    37. data->pop_back();
    38. }
    39. void StrBlob::check(size_type i, const string& msg) const {
    40. if(i >= data->size()) {
    41. throw out_of_range(msg);
    42. }
    43. }
    44. class StrBlobPtr {
    45. public:
    46. StrBlobPtr() : curr(0) { }
    47. StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
    48. std::string& deref() const;
    49. StrBlobPtr& incr();
    50. size_t pos() const;
    51. private:
    52. std::shared_ptr> check(std::size_t, const std::string&) const;
    53. std::weak_ptr> wptr;
    54. std::size_t curr;
    55. };
    56. std::string& StrBlobPtr::deref() const {
    57. auto p = check(curr, "dereference past end");
    58. return (*p)[curr];
    59. }
    60. StrBlobPtr& StrBlobPtr::incr() {
    61. check(curr, "increment past end of StrBlobPtr");
    62. ++curr;
    63. return *this;
    64. }
    65. std::shared_ptr> StrBlobPtr::check(std::size_t i, const std::string &msg) const {
    66. auto ret = wptr.lock();
    67. if(!ret)
    68. throw std::runtime_error("unbound StrBlobPtr");
    69. if(i >= ret->size())
    70. throw std::out_of_range(msg);
    71. return ret;
    72. }
    73. size_t StrBlobPtr::pos() const {
    74. return curr;
    75. }
    76. StrBlobPtr StrBlob::begin() {
    77. return StrBlobPtr(*this);
    78. }
    79. StrBlobPtr StrBlob::end() {
    80. auto ret = StrBlobPtr(*this, data->size());
    81. return ret;
    82. }

    12.20:

    1. int main() {
    2. std::string str{};
    3. StrBlob str_blob{};
    4. while(cin >> str) {
    5. str_blob.push_back(str);
    6. }
    7. for (StrBlobPtr pbeg(str_blob.begin()), pend(str_blob.end()); pbeg.pos() != pend.pos(); pbeg.incr()) {
    8. cout << pbeg.deref() << std::endl;
    9. }
    10. }

    12.21:

    将合法性检查与元素获取的返回语句分离开来,代码更清晰易读。

    12.22:

    StrBlobPtr(const StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }

    12.2 动态数组

    12.2.1 new和数组(12.23 ~ 12.25)

    12.23:

    1. // dynamically allocated array of char
    2. char *concatenate_string = new char[strlen("hello " "world") + 1]();
    3. strcat(concatenate_string, "hello ");
    4. strcat(concatenate_string, "world");
    5. std::cout << concatenate_string << std::endl;
    6. delete [] concatenate_string;
    7. // std::string
    8. std::string str1{ "hello " }, str2{ "world" };
    9. std::cout << str1 + str2 << std::endl;
    10. // hello world
    11. // hello world
    12. // copy from https://github.com/Mooophy/Cpp-Primer/blob/master/ch12/ex12_23.cpp

    12.24:

    1. string str;
    2. cin >> str;
    3. char *input = new char[str.size() + 1]();
    4. strcat(input, str.c_str());
    5. cout << input << endl;
    6. delete [] input;
    7. // input: helloworld
    8. // output: helloworld

    12.25:

    delete [] pa;

    12.2.2 allocator(12.26)

    12.26:

    1. allocator alloc; // 可以分配string的allocator对象
    2. auto const p = alloc.allocate(n); // 分配n个未初始化的string
    3. string s;
    4. auto q = p;
    5. while(cin >> s && q != p + n)
    6. alloc.construct(q++, s);
    7. // 输出 & 析构
    8. while(q != p) {
    9. cout << *--q << endl;
    10. alloc.destroy(q);
    11. }
    12. // 释放内存
    13. alloc.deallocate(p, n);

    12.3 使用标准库:文本查询程序

    12.3.1 文本查询程序设计(12.27 ~ 12.29)

    12.27:

    1. class TextQuery{
    2. public:
    3. TextQuery(ifstream &infile);
    4. void query(string s);
    5. private:
    6. vector line_text_{};
    7. mapsize_t>> word_lines_{};
    8. };
    9. TextQuery::TextQuery(ifstream &infile){
    10. string line_string;
    11. size_t line = 1;
    12. while(getline(infile, line_string)){
    13. cout << line_string << endl;
    14. line_text_.push_back(line_string);
    15. istringstream stream(line_string);
    16. string word;
    17. while(stream >> word){
    18. auto iter = word_lines_.find(word);
    19. set<size_t> lines{};
    20. if(iter != word_lines_.end()) {
    21. lines = iter->second;
    22. }
    23. lines.insert(line);
    24. word_lines_[word] = lines;
    25. }
    26. line++;
    27. }
    28. }
    29. void TextQuery::query(string s) {
    30. auto iter = word_lines_.find(s);
    31. if(iter != word_lines_.end()){
    32. auto lines = iter->second;
    33. cout << s << " occurs " << lines.size() << " times" << endl;
    34. for(const auto index : lines) {
    35. if(index >= 1 && index <= line_text_.size()){
    36. cout << "(line "<< index << ") " << line_text_[index - 1] << endl;
    37. }
    38. }
    39. }
    40. }
    41. void runQueries(ifstream &infile) {
    42. // infile 是一个ifstream,指向我们要处理的文件
    43. TextQuery tq(infile); // 保存文件并建立查询map
    44. // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
    45. while(true) {
    46. cout << "enter word to look for, or q to quit: ";
    47. string s;
    48. // 若遇到文件尾或用户输入了'q'时循环终止
    49. if(!(cin >> s) || s == "q") break;
    50. // 指向查询并打印结果
    51. //print(cout, tq.query(s)) << endl;
    52. tq.query(s);
    53. }
    54. }
    55. int main() {
    56. ifstream fstrm1("1.txt");
    57. runQueries(fstrm1);
    58. }
    59. // 自己写的 有点简单 只用了一个类 也没有用到智能指针
    60. // 输入是文件1.txt 会打印出输入的内容
    61. /*
    62. brb be right back
    63. k okay?
    64. y why
    65. r are
    66. u you
    67. pic picture
    68. thk thanks~
    69. 18r later
    70. k okay!
    71. enter word to look for, or q to quit: k
    72. k occurs 2 times
    73. (line 2) k okay?
    74. (line 9) k okay!
    75. enter word to look for, or q to quit: r
    76. r occurs 1 times
    77. (line 4) r are
    78. enter word to look for, or q to quit: q
    79. */
    80. // https://github.com/Mooophy/Cpp-Primer/tree/master/ch12 移除了输入中的标点符号

    12.28:

    1. int main() {
    2. ifstream fstrm1("1.txt");
    3. vector line_text{};
    4. mapsize_t>> word_lines{};
    5. string line_string;
    6. size_t line = 1;
    7. while(getline(fstrm1, line_string)){
    8. cout << line_string << endl;
    9. line_text.push_back(line_string);
    10. istringstream stream(line_string);
    11. string word;
    12. while(stream >> word){
    13. auto iter = word_lines.find(word);
    14. set<size_t> lines{};
    15. if(iter != word_lines.end()) {
    16. lines = iter->second;
    17. }
    18. lines.insert(line);
    19. word_lines[word] = lines;
    20. }
    21. line++;
    22. }
    23. while(true) {
    24. cout << "enter word to look for, or q to quit: ";
    25. string s;
    26. // 若遇到文件尾或用户输入了'q'时循环终止
    27. if(!(cin >> s) || s == "q") break;
    28. // 指向查询并打印结果
    29. //print(cout, tq.query(s)) << endl;
    30. auto iter = word_lines.find(s);
    31. if(iter != word_lines.end()){
    32. auto lines = iter->second;
    33. cout << s << " occurs " << lines.size() << " times" << endl;
    34. for(const auto index : lines) {
    35. if(index >= 1 && index <= line_text.size()){
    36. cout << "(line "<< index << ") " << line_text[index - 1] << endl;
    37. }
    38. }
    39. }
    40. }
    41. }
    42. // 输出与上面一致

    12.29:

    1. void runQueries(ifstream &infile) {
    2. // infile 是一个ifstream,指向我们要处理的文件
    3. TextQuery tq(infile); // 保存文件并建立查询map
    4. // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
    5. do{
    6. cout << "enter word to look for, or q to quit: ";
    7. string s;
    8. // 若遇到文件尾或用户输入了'q'时循环终止
    9. if(!(cin >> s) || s == "q") break;
    10. // 指向查询并打印结果
    11. //print(cout, tq.query(s)) << endl;
    12. tq.query(s);
    13. }
    14. while(true);
    15. }
    16. // 倾向于直接用while,清晰
    17. // https://www.cnblogs.com/songshuguiyu/p/9598196.html 这里写do while更简洁…

    12.3.2 文本查询程序类的定义(12.30 ~ 12.33)

    12.30:

    1. class QueryResult; // 为了定义函数query的返回类型
    2. class TextQuery {
    3. public:
    4. using line_no = std::vector::size_type;
    5. TextQuery(std::ifstream&);
    6. QueryResult query(const std::string&) const;
    7. private:
    8. std::shared_ptr> file; // 输入文件
    9. // 每个单词到它所在的行号的集合的映射
    10. std::map>> wm;
    11. };
    12. TextQuery::TextQuery(ifstream &is) : file(new vector) {
    13. string text;
    14. while(getline(is, text)) { // 对文件中每一行
    15. file->push_back(text); // 保存此行文本
    16. int n = file->size() - 1; // 当前行号
    17. istringstream line(text); // 将行文本分解为单词
    18. string word;
    19. while(line >> word) { // 对行中每个单词
    20. // 如果单词不在wm中,以之为下标在wm中添加一项
    21. auto &lines = wm[word]; // lines是shared_ptr(如果lines为空没有使用引用是会失败的)
    22. if(!lines) // 在第一次遇到此单词时,此指针为空
    23. lines.reset(new set); // 分配一个新的set
    24. lines->insert(n); // 将此行号插入set中
    25. }
    26. }
    27. }
    28. class QueryResult {
    29. friend std::ostream& print(std::ostream&, const QueryResult&); // 友元函数不需要放在public或private里吗?
    30. public:
    31. QueryResult(std::string s, std::shared_ptr> p, std::shared_ptr> f) : sought(s), lines(p), file(f) { }
    32. private:
    33. std::string sought; // 查询单词
    34. std::shared_ptr> lines; // 出现的行号
    35. std::shared_ptr> file; // 输入文字
    36. };
    37. QueryResult TextQuery::query(const string & sought) const {
    38. // 如果未找到sought,将返回指向此set的指针
    39. static shared_ptr> nodata(new set);
    40. // 使用find而不是下标运算符来查找单词,避免将单词添加到wm中!
    41. auto loc = wm.find(sought);
    42. if(loc == wm.end())
    43. return QueryResult(sought, nodata, file); // 未找到
    44. else
    45. return QueryResult(sought, loc->second, file);
    46. }
    47. void runQueries(ifstream &infile) {
    48. // infile 是一个ifstream,指向我们要处理的文件
    49. TextQuery tq(infile); // 保存文件并建立查询map
    50. // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
    51. while(true) {
    52. cout << "enter word to look for, or q to quit: ";
    53. string s;
    54. // 若遇到文件尾或用户输入了'q'时循环终止
    55. if(!(cin >> s) || s == "q") break;
    56. // 指向查询并打印结果
    57. print(cout, tq.query(s)) << endl;
    58. }
    59. }
    60. string make_plural(size_t ctr, const string &word, const string &ending) {
    61. return ctr > 1 ? word + ending : word;
    62. }
    63. ostream &print(ostream &os, const QueryResult &qr) {
    64. // 如果找到了单词,打印出现次数和所有出现的位置
    65. os << qr.sought << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "times", "s") << endl;
    66. // 打印单词出现的每一行
    67. for(auto num : *qr.lines) // 对set中每个单词
    68. // 避免行号从0开始给用户带来的困惑
    69. os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
    70. return os;
    71. }
    72. int main() {
    73. ifstream fstrm1("1.txt");
    74. runQueries(fstrm1);
    75. }
    76. // 12.27写过了,这里将书中的代码copy运行

    12.31:

    一行中有两个重复的单词,输出时,如果vector不过滤,会将这一行输出两遍,使用set不用过滤。

    12.32:

    1. class StrBlobPtr;
    2. class StrBlob {
    3. public:
    4. typedef std::vector::size_type size_type;
    5. friend class StrBlobPtr;
    6. StrBlob();
    7. StrBlob(std::initializer_list il);
    8. size_type size() const { return data->size(); }
    9. bool empty() const { return data->empty(); }
    10. void push_back(const std::string& t) { data->push_back(t); }
    11. void pop_back();
    12. std::string& front();
    13. std::string& back();
    14. StrBlobPtr begin();
    15. StrBlobPtr end();
    16. private:
    17. std::shared_ptr> data;
    18. void check(size_type i, const std::string& msg) const;
    19. };
    20. StrBlob::StrBlob() : data(make_shared>()) {
    21. }
    22. StrBlob::StrBlob(initializer_list il) : data(make_shared>(il)) {
    23. }
    24. string& StrBlob::front() {
    25. check(0, "front on empty StrBlob");
    26. return data->front();
    27. }
    28. string& StrBlob::back() {
    29. check(0, "back on empty StrBlob");
    30. return data->back();
    31. }
    32. void StrBlob::pop_back() {
    33. check(0, "pop_back on empty StrBlob");
    34. data->pop_back();
    35. }
    36. void StrBlob::check(size_type i, const string& msg) const {
    37. if(i >= data->size()) {
    38. throw out_of_range(msg);
    39. }
    40. }
    41. class StrBlobPtr {
    42. public:
    43. StrBlobPtr() : curr(0) { }
    44. StrBlobPtr(const StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
    45. std::string& deref() const;
    46. StrBlobPtr& incr();
    47. size_t pos() const;
    48. private:
    49. std::shared_ptr> check(std::size_t, const std::string&) const;
    50. std::weak_ptr> wptr;
    51. std::size_t curr;
    52. };
    53. std::string& StrBlobPtr::deref() const {
    54. auto p = check(curr, "dereference past end");
    55. return (*p)[curr];
    56. }
    57. StrBlobPtr& StrBlobPtr::incr() {
    58. check(curr, "increment past end of StrBlobPtr");
    59. ++curr;
    60. return *this;
    61. }
    62. std::shared_ptr> StrBlobPtr::check(std::size_t i, const std::string &msg) const {
    63. auto ret = wptr.lock();
    64. if(!ret)
    65. throw std::runtime_error("unbound StrBlobPtr");
    66. if(i >= ret->size())
    67. throw std::out_of_range(msg);
    68. return ret;
    69. }
    70. size_t StrBlobPtr::pos() const {
    71. return curr;
    72. }
    73. StrBlobPtr StrBlob::begin() {
    74. return StrBlobPtr(*this);
    75. }
    76. StrBlobPtr StrBlob::end() {
    77. auto ret = StrBlobPtr(*this, data->size());
    78. return ret;
    79. }
    80. class QueryResult; // 为了定义函数query的返回类型
    81. class TextQuery {
    82. public:
    83. using line_no = std::vector::size_type;
    84. TextQuery(std::ifstream&);
    85. QueryResult query(const std::string&) const;
    86. private:
    87. std::shared_ptr> file; // 输入文件
    88. std::shared_ptr file2;
    89. // 每个单词到它所在的行号的集合的映射
    90. std::map>> wm;
    91. };
    92. TextQuery::TextQuery(ifstream &is) : file2(make_shared()) {
    93. string text;
    94. while(getline(is, text)) { // 对文件中每一行
    95. file2->push_back(text); // 保存此行文本
    96. int n = file2->size() - 1; // 当前行号
    97. istringstream line(text); // 将行文本分解为单词
    98. string word;
    99. while(line >> word) { // 对行中每个单词
    100. // 如果单词不在wm中,以之为下标在wm中添加一项
    101. auto &lines = wm[word]; // lines是shared_ptr(如果lines为空没有使用引用是会失败的)
    102. if(!lines) // 在第一次遇到此单词时,此指针为空
    103. lines.reset(new set); // 分配一个新的set
    104. lines->insert(n); // 将此行号插入set中
    105. }
    106. }
    107. }
    108. class QueryResult {
    109. friend std::ostream& print(std::ostream&, const QueryResult&); // 友元函数不需要放在public或private里吗?
    110. public:
    111. QueryResult(std::string s, std::shared_ptr> p, std::shared_ptr f) : sought(s), lines(p), file2(f) { }
    112. private:
    113. std::string sought; // 查询单词
    114. std::shared_ptr> lines; // 出现的行号
    115. std::shared_ptr> file; // 输入文字
    116. std::shared_ptr file2; // 输入文字
    117. };
    118. QueryResult TextQuery::query(const string & sought) const {
    119. // 如果未找到sought,将返回指向此set的指针
    120. static shared_ptr> nodata(new set);
    121. // 使用find而不是下标运算符来查找单词,避免将单词添加到wm中!
    122. auto loc = wm.find(sought);
    123. if(loc == wm.end())
    124. return QueryResult(sought, nodata, file2); // 未找到
    125. else
    126. return QueryResult(sought, loc->second, file2);
    127. }
    128. void runQueries(ifstream &infile) {
    129. // infile 是一个ifstream,指向我们要处理的文件
    130. TextQuery tq(infile); // 保存文件并建立查询map
    131. // 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
    132. while(true) {
    133. cout << "enter word to look for, or q to quit: ";
    134. string s;
    135. // 若遇到文件尾或用户输入了'q'时循环终止
    136. if(!(cin >> s) || s == "q") break;
    137. // 指向查询并打印结果
    138. print(cout, tq.query(s)) << endl;
    139. }
    140. }
    141. string make_plural(size_t ctr, const string &word, const string &ending) {
    142. return ctr > 1 ? word + ending : word;
    143. }
    144. ostream &print(ostream &os, const QueryResult &qr) {
    145. // 如果找到了单词,打印出现次数和所有出现的位置
    146. os << qr.sought << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "times", "s") << endl;
    147. // 打印单词出现的每一行
    148. for(auto num : *qr.lines) { // 对set中每个单词
    149. // 避免行号从0开始给用户带来的困惑
    150. StrBlobPtr p(*qr.file2, num);
    151. os << "\t(line " << num + 1 << ") " << p.deref() << endl;
    152. }
    153. return os;
    154. }
    155. int main() {
    156. ifstream fstrm1("1.txt");
    157. runQueries(fstrm1);
    158. }
    159. // 将之前的StrBlob和StrBlobPtr也放过来了
    160. // 里面有一些上题无用的变量file没有删哇~

    12.33:

    1. class QueryResult {
    2. using ResultIter = std::set::iterator;
    3. friend std::ostream& print(std::ostream&, const QueryResult&); // 友元函数不需要放在public或private里吗?
    4. public:
    5. QueryResult(std::string s, std::shared_ptr> p, std::shared_ptr f) : sought(s), lines(p), file2(f) { }
    6. ResultIter begin() const { return nos->begin(); }
    7. ResultIter end() const { return nos->end(); }
    8. shared_ptr get_file() const { return file2; }
    9. private:
    10. std::string sought; // 查询单词
    11. std::shared_ptr> lines; // 出现的行号
    12. std::shared_ptr> file; // 输入文字
    13. std::shared_ptr file2; // 输入文字
    14. shared_ptr> nos;
    15. };
    16. // copy了一下这里的https://github.com/Mooophy/Cpp-Primer/blob/master/ch12/ex12_33.h

  • 相关阅读:
    Prometheus服务发现之kubernetes_sd_config
    CleanMyMac XMac苹果电脑专属系统优化工具
    自制Linux功能板
    用滑动条做调色板---cv2.getTrackbarPos(),cv2.creatTrackbar()
    【数据结构】树和二叉树的概念及结构(一)
    get和post
    quill富文本工具栏添加行高配置
    Spring Security加密和匹配
    C++进阶篇4---番外-AVL树
    27.在springboot中使用thymeleaf的属性inline(text, javascript 和 none)
  • 原文地址:https://blog.csdn.net/zjzytnn/article/details/125471550