zoukankan      html  css  js  c++  java
  • c++ primer 第五版第十二章

    12.01 在此代码的结尾,b1和b2各包含多少元素?

    StrBlob b1;
    {
        strBlob b2 = {"a", "an", "the"};
        b1 = b2;
        b2.push_back("about");
    }
    // b1 包含3个元素,b2包含4个元素。
    

    12.02 编写你自己的StrBlob类,包含const版本的front和back。

    class StrBlob
    {
    public:
        typedef vector<string>::size_type size_type;
        StrBlob();
        StrBlob(initializer_list<string> il);
        size_type size() const{ return data->size(); }
        bool empty() { return data->empty(); }
        void push_back(const string& t) { data->push_back(t); }
        void pop_back();
        string& front();
        string& back();
        const string& front() const;
        const string& back() const;
    private:
        shared_ptr<vector<string>> data;
        void check (size_type i, const string& msg) const;
    };
    
    StrBlob::StrBlob() : data(shared_ptr<vector<string>>()) {}
    StrBlob::StrBlob(initializer_list<string> il) : data(shared_ptr<vector<string>> il) {}
    StrBlob::void 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();
    }
    
    const string& StrBlob::front() const
    {
        check (0, "front on empty StrBlob");
        return data->front;
    }
    
    const string& StrBlob::back() const
    {
        check (0, "back on empty StrBlob");
        return data->back();
    }
    
    void StrBlob::pop_back()
    {
        check (0, "back on empty StrBlob");
        return data->pop_back();
    }
    

    12.03 StrBlob需要const版本的push_back和pop_back吗?如果需要,添加进去。否则,解释为什么不需要。

    void StrBlob::pop_back() const
    {
        check(0, "pop_back on empty wy_StrBlob");
        data->pop_back();
    }
    

    如果想加的话确实可以实现,但并没有什么合理的理由。加了编译器也不会报错,因为其并未改变指针(不是指针所指的数据)。const指针完全合法。

    https://stackoverflow.com/questions/20725190/operating-on-dynamic-memory-is-it-meaningful-to-overload-a-const-memeber-functi

    12.04 在我们的check函数中,没有检查i是否大于0。为什么可以忽略这个检查?

    因为size_type是unsigned类型,本身就大于等于0。即使将一个负数给其赋值,它还是大于0.

    12.05 我们未编写接受一个initializer_list explicit参数的构造函数。讨论这个设计策略的优点和缺点。

    "explicit"关键字将会阻止initializer_list 自动转换为StrBlob。这个设计不容易使用,但可以防止使用出错。

    12.06 编写函数,返回一个动态分配的int的vector。将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在vector元素中。再将vector传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector。

    vector<int>* applicateVector()
    {
        return new (nothrow) vector<int>();
    }
    
    void readToVector(vector<int>* ivec)
    {
        if (nullptr == ivec) {
            cout << "vector is illegal." << endl;
            exit(1);
        }
    
        int num;
        while (cin >> num) {
            (*ivec).push_back(num);
        }
    }
    
    void printVector(vector<int>* ivec)
    {
        if (nullptr == ivec) {
            cout << "vector is illegal." << endl;
            exit(1);
        }
    
        for (auto i : *ivec) {
            cout << i << " ";
        }
        cout << endl;
    }
    
    void test1206()
    {
        vector<int> *ivec = applicateVector();
        if (nullptr == ivec) {
            cout << "vector is illegal." << endl;
            exit(1);
        }
        readToVector (ivec);
        printVector (ivec);
    
        delete ivec;
    }
    

    12.07 重做上一题,这次使用shared_ptr而不是内置指针。

    shared_ptr<vector<int>> applicateVectorPtr()
    {
        return make_shared<vector<int>>();
    }
    
    void readToVectorPtr(shared_ptr<vector<int>> ivec)
    {
        if (!ivec) {
            cout << "vector is illegal." << endl;
            exit(1);
        }
    
        int num;
        while (cin >> num) {
            ivec->push_back(num);
        }
    }
    
    void printVectorPtr(shared_ptr<vector<int>> ivec)
    {
        if (!ivec) {
            cout << "vector is illegal." << endl;
            exit(1);
        }
    
        for (auto i : *ivec) {
            cout << i << " ";
        }
        cout << endl;
    }
    
    void test1207()
    {
        shared_ptr<vector<int>> p;
        p = applicateVectorPtr();
        readToVectorPtr(p);
        printVectorPtr(p);
    }
    

    12.08 下面的函数是否有错误?如果有,解释错误原因。

    bool b() {
        int *p = new int;
        // ...
        return p;
    }
    

    函数定义的返回值类型与实际的返回类型不匹配。int* 会转换为bool类型。这会导致p将没有机会被delete,最终造成内存泄漏。

    12.09 解释下面代码执行的结果:

    int *q = new int(42), *r = new int(100);
    r = q;
    auto q2 = make_shared<int>(42), r2 = make_shared<int>(100);
    r2 = q2;
    
    1. r = q,则r原来的空间没有指针指向,因此也不会被释放,造成内存泄漏。
    2. r2 = q2, q2的引用计数+1,r2的引用计数-1,变为0。r2原来指向的那块空间会被释放。

    12.10 下面的代码调用了413页中定义的process函数,解释此调用是否正确,如果不正确,应如何修改?

    shared_ptr<int> p (new int(42));
    process (shared_ptr<int>(p));
    // 此调用正确。
    

    12.11 如果我们像下面这样调用process,会发生什么?

    process(shared_ptr<int>(p.get()));
    

    传给process的是由p.get()初始化的一个新的shared_ptr,与p指向同一块内存。在process函数结束时,新的shared_ptr被释放,p就变成了一个空悬指针。

    12.12 p 和q的定义如下,对应接下来的对process的每个调用,如果合法,解释它做了什么,如果不合法,解释错误原因:

    auto p = new int();
    auto sp = make_shared<int>();
    
    (a) process (sp);			// 合法,将一个shared_ptr传给process。
    (b) process(new int());		// 不合法,不能将内置指针隐式转换为shared_ptr.
    (c) process (p);			// 不合法,不能将内置指针隐式转换为shared_ptr.
    (d) process (shared ptr<int>(p));	// 合法。但不建议这样使用,智能指针和常量指针混用容易引起问题,比如有可能被释放两次。
    

    12.13 如果执行下面的代码,会发生什么?

    auto sp = make_shared<int>();
    auto p = sp.get();
    delete p;
    

    使用sp初始化p,p和sp指向同一块内存。delete p之后,这块内存被释放,sp也会被释放,导致同一块内存被释放两次。

    12.14 编写你自己版本的用shared_ptr管理connection的函数。

    struct destination
    {
        destination(const string& ip, const string& port) : m_ip(ip), m_port(port) {}
        string m_ip, m_port;
    };
    struct connection
    {
        connection(string& ip, string& port) : m_ip(ip), m_port(port) {}
        string m_ip, m_port;
    };
    
    connection connect(destination* pdes)
    {
        shared_ptr<connection> spConn (new connection(pdes->m_ip, pdes->m_port));
        cout << "create a connection " << spConn.use_count() << " to " << pdes->m_ip << " : " << pdes->m_port << endl;
        return *spConn;
    }
    
    void disconnection(connection pConn)
    {
        cout << "close the connection " << pConn.m_ip << " : " << pConn.m_port << endl;
    }
    
    void end_connection(connection* p)
    {
        disconnection(*p);
    }
    
    void f(destination* d)
    {
        connection c = connect(d);
        shared_ptr<connection> p (&c, end_connection);
    }
    
    void test1214()
    {
        destination d ("192.21.4.110", "8088");
        f (&d);
    }
    

    12.15 重写第一题的程序,用lambda代替end_connection函数。

    // 将函数f改为:
    void f(destination* d)
    {
        connection c = connect(d);
        shared_ptr<connection> p (&c, [](connection *p) {disconnection(*p);});
    }
    

    12.16 如果你试图拷贝或赋值unique_ptr,编译器并不总是能给出易于理解的错误信息。编写包含这种错误的程序,观察编译器如何诊断这种错误。

    void test1215()
    {
        unique_ptr<int> p1 (new int(42));
        unique_ptr<int> p2 = p1;
        unique_ptr<int> p3 (p1);
    }
    // 赋值的错误提示是:error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
    // 拷贝的错误提示: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<int>]'
    

    12.17 下面的unique_ptr声明中,哪些是合法的,哪些可能导致后续的程序错误?解释每个错误的问题在哪里。

    int ix = 1024, *pi = &ix, *pi2 = new int (2048);
    typedef unique_ptr<int> IntP;
    (a) IntP p0 (ix);		// 不合法,unique_ptr只能绑定到new返回的指针上。
    (b) IntP p1 (pi);		// 编译时无报错,在我的编译器上也可以正确运行。但不建议使用,因为使用智能指针unique_ptr,在检测到指针超出范围时,编译器会调用delete去释放,但pi不是又new分配的,因此就不能使用delete去释放,所以当p1非法时,就会由操作系统抛出错误,造成运行时错误。
    (c) IntP p2 (pi2);		// 可以使用,但有可能在运行时产生空悬指针pi2,因为运行时,p2所指空间可能被释放,pi2就成为了空悬指针。
    (d) IntP p3 (&ix);		// 同b,编译器不会报错,但无法使用delete释放。
    (e) IntP p4 (new int(2048));	// 合法,推荐使用
    (f) IntP p5 (p2.get());			// 不合法,使用get初始化一个智能指针,p2和p5指向同一块内存,当指针非法,智能指针会自动delete,此时这块内存会被二次delete。
    

    12.18 shared_ptr为什么没有release成员?

    release的作用是交出指针指向对象的控制权,但是shared_ptr是多对一的关系,一个shared_ptr交出控制权,其它shared_ptr依旧可以控制这个对象。因此这个方法对shared_ptr无意义。

    12.19 定义你自己版本的StrBlobPtr,更新StrBlobPtr类,加入恰当的friend声明及begin和end成员。

    class StrBlobPtr;
    
    class StrBlob
    {
        friend class StrBlobPtr;
    public:
        StrBlobPtr begin();
        StrBlobPtr end();
        typedef vector<string>::size_type size_type;
    
        StrBlob();
        StrBlob(initializer_list<string> il);
        size_type size() const{ return data->size(); }
        bool empty() { return data->empty(); }
        void push_back(const string& t) { data->push_back(t); }
        void pop_back();
        string& front();
        string& back();
        const string& front() const;
        const string& back() const;
    
    private:
        shared_ptr<vector<string>> data;
        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:
        // 若检查成功,check返回一个指向vector的shared_ptr.
        shared_ptr<vector<string>> check(size_t, const string&) const;
        weak_ptr<vector<string>> wptr;      // 保存一个weak_ptr,意味着vector有可能被销毁。
        size_t curr;        // 在数组中当前的位置
    };
    StrBlobPtr StrBlob::begin()
    {
        return StrBlobPtr (*this);
    }
    
    StrBlobPtr StrBlob::end()
    {
        auto ret = StrBlobPtr(*this, data->size());
        return ret;
    }
    
    // begin()和end()函数的定义必须在StrBlobPtr类定义之后,否则会报错(StrBlobPtr是不完全类型),最好的方法是使用.h文件实现声明和定义分离。
    

    12.20 编写程序,逐行读入一个输入文件,将内容存入一个StrBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素。

    void test1220()
    {
        ifstream ifs ("C:/Users/tutu/Documents/code/cpp_primer/ch12/infile.txt");
        StrBlob strb;
        string line;
        StrBlobPtr pbeg, pend;
    
        if (ifs) {
            while (getline(ifs, line)) {
                strb.push_back(line);
            }
        }
        for (pbeg=strb.begin(), pend=strb.end(); pbeg != pend; pbeg.incr()) {
            cout << pbeg.deref() << endl;
        }
    }
    

    12.21 也可以这样编写StrBlobPtr的deref成员:

    std::string& deref() const
    {
        return (*check(curr, "dereference past end"))[curr];
    }
    

    你认为哪个版本更好?为什么?

    原始的版本更好,其更易读。

    12.22 为了能让StrBlobPtr使用const StrBlob,你觉得应该如何修改?定义一个名为ConstStrBlobPtr的类,使其能够指向const StrBlob。

    class ConstStrBlobPtr {
    public:
        ConstStrBlobPtr() : curr(0) {}
        ConstStrBlobPtr (const StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {}
        string& deref() const;
        ConstStrBlobPtr& incr();     // 前缀递增
        bool operator!= (const ConstStrBlobPtr& pblob) { return pblob.curr != curr; }
    private:
        // 若检查成功,check返回一个指向vector的shared_ptr.
        shared_ptr<vector<string>> check(size_t, const string&) const;
        weak_ptr<vector<string>> wptr;      // 保存一个weak_ptr,意味着vector有可能被销毁。
        size_t curr;        // 在数组中当前的位置
    };
    
    要在StrBlob类中加:
    friend class ConstStrBlobPtr;
    ConstStrBlobPtr cbegin();
    ConstStrBlobPtr cend();
    
    测试:
    void test1222()
    {
        ifstream ifs ("C:/Users/tutu/Documents/code/cpp_primer/ch12/infile.txt");
        StrBlob strb;
        string line;
        ConstStrBlobPtr pcbeg, pcend;
    
        if (ifs) {
            while (getline(ifs, line)) {
                strb.push_back(line);
            }
        }
        for (pcbeg=strb.cbegin(), pcend=strb.cend(); pcbeg != pcend; pcbeg.incr()) {
            cout << pcbeg.deref() << endl;
        }
    }
    

    12.23 编写一个程序,连接两个字符串字面常量,将结果保存在一个动态分配的char数组中。重写这个程序,连接两个标准库string对象。

    void test1223()
    {
        string s1 = "Hello ";
        string s2 = "world";
    
        int len1 = s1.size(), len2 = s2.size();
        char* c = new char[len1+len2+1]();
    
        strcat (c, s1.c_str());
        strcat (c, s2.c_str());
    
        cout << c << endl;
        delete[] c;
    
        string str = s1 + s2;
        cout << str << endl;
    }
    

    12.24 编写一个程序,从标准输入读取一个字符串,存入一个动态分配的字符数组中。描述你的程序如何处理变长输入。测试你的程序,输入一个超出你分配的数组长度的字符串。

    void test1224()
    {
        string str;
    
        cout << "Please input a string: ";
        getline (cin, str);
    
        char* cArray = new char[str.size()+1]();
        strcat(cArray, str.c_str());
    
        cout << cArray << endl;
        delete[] cArray;
    }
    // 处理变长输入:输入之后再根据输入字符串的长度分配内存,不会超出。
    

    12.25 给定下面的new表达式,你应该如何释放pa?

    int *pa = new int[10];
    // 释放:
    // delete[] pa;
    

    12.26 用allocator重写427页中的程序。

    void test1226()
    {
        allocator<string> alloc;
        auto const p = alloc.allocate(10);
        string s;
        auto q = p;
    
        while (cin >> s && q != p+10) {
          alloc.construct (q++, s);
        }
    
        while (q != p) {
            cout << *--q << endl;
            alloc.destroy(q);
        }
        alloc.deallocate (p, 10);
    }
    

    12.27 TextQuery和QueryResult类只使用了我们已经介绍过的语言和标准库特性。不要提前看后续章节内容,只用已经学到的知识对这两个类编写你自己的版本。

    class QueryResult;
    class TextQuery
    {
    public:
        using line_no = std::vector<std::string>::size_type;
        TextQuery(std::ifstream& ifs);
        QueryResult query (const std::string& word) const;
    
    private:
        std::shared_ptr<std::vector<std::string>> sp_text;
        // 每个单词到它所出现的行号的映射
        std::map<std::string, std::shared_ptr<std::set<line_no>>> sp_dictionary;
    };
    
    class QueryResult
    {
    public:
         friend std::ostream& print (std::ostream&, const QueryResult&);
    public:
        QueryResult(const std::string& s,
                    std::shared_ptr<std::set<TextQuery::line_no>> sp_set,
                    std::shared_ptr<std::vector<std::string>> sp_vec):
                sought (s), lines (sp_set), file (sp_vec) {}
    
    
    private:
        std::string sought;     // 要查找的单词
        std::shared_ptr<std::set<TextQuery::line_no>> lines;       // 出现的行号
        std::shared_ptr<std::vector<std::string>> file;     // 输入文件
    //    vector<string> occur_line;
    };
    
    std::ostream& print (std::ostream&, const QueryResult&);
    

    12.28 编写程序实现文本查询,不要定义类来管理数据。你的程序应该接受一个文件,并与用户交互来查询单词。使用vector、map和set容器来保存来自文件的数据并生产查询结果。

    #include <map>
    #include <set>
    #include <sstream>
    #include <algorithm>
    #include <ctype.h>
    #include <iostream>
    #include <memory>
    #include <vector>
    #include <string>
    #include <fstream>
    
    using std::string;
    using std::vector;
    
    void test1228()
    {
        std::ifstream ifs ("C:/Users/tutu/Documents/code/cpp_primer/ch12/textQuery.cpp");
        std::ofstream ofs ("C:/Users/tutu/Documents/code/cpp_primer/ch12/text.txt");
        string tmp_line;
        vector<string> line_str;
        decltype (line_str.size()) lineNo{0};
        std::map <string, std::set<unsigned int>> dictionary;
    
        while (getline(ifs, tmp_line)) {
            line_str.push_back(tmp_line);
            ++ lineNo;
            std::istringstream line_stream (tmp_line);
            string unique_word, text;
            for (unique_word, text; line_stream >> text; unique_word.clear()) {
                // 把每行的以空格隔开的单词拷贝到unique_word中,标点符号除外。
                std::remove_copy_if (text.begin(), text.end(), back_inserter(unique_word), ispunct);
                // 把每个出现的单词和行号都放入map中,如果已经存在,则只插入行号。
                dictionary[unique_word].insert(lineNo);
            }
        }
    
        string s;
        while (true) {
            std::cout << "enter a word to search, or q to quit: ";
            if (!(std::cin >> s) || (s == "q")) {
                break;
            }
            auto found_iter = dictionary.find(s);
            if (found_iter != dictionary.end()) {
                std::cout << s << " occurs " << found_iter->second.size() << " times." << std::endl;
                for (auto i : found_iter->second) {
                    std::cout << "	(line" << i << ")" << line_str.at(i-1) << std::endl;
                }
            }
            else {
                std::cout << "Not found it." << std::endl;
            }
        }
    }
    

    这段代码,如果使用using namespace std; 则remove_copy_if函数就会报错,提示无法解析的重载函数类型。

    12.29 我们曾经用do while 循环来编写管理用户交互的循环。用do while重写本节程序,解释你倾向于哪个版本,为什么。

    // 用do...while改写如下:
    do {
            std::cout << "enter a word to search, or q to quit: ";
            if (!(std::cin >> s) || (s == "q")) {
                break;
            }
            auto found_iter = dictionary.find(s);
            if (found_iter != dictionary.end()) {
                std::cout << s << " occurs " << found_iter->second.size() << " times." << std::endl;
                for (auto i : found_iter->second) {
                    std::cout << "	(line" << i << ")" << line_str.at(i-1) << std::endl;
                }
            }
            else {
                std::cout << "Not found it." << std::endl;
            }
        } while (true);
    // 使用do...while看起来简洁一点。
    

    12.30 定义你自己版本的 TextQuery和QueryResult类,并执行12.3.1节中的runQueries函数。

    // 头文件如12.27题所列,cpp文件如下:
    #include "textQuery.h"
    using namespace std;
    
    TextQuery::TextQuery(std::ifstream& ifs) : sp_text (new vector<string>)
    {
        string text;
    
        while (getline(ifs, text)) {
            sp_text->push_back(text);
            int n = sp_text->size() - 1;    // 当前行号
            istringstream line (text);
            string word;
            while (line >> word) {
                auto &lines = sp_dictionary[word];
    
                if (!lines) {
                    lines.reset (new set<line_no>);
                }
                lines->insert(n);
            }
        }
    }
    
    QueryResult TextQuery::query(const std::string& word) const
    {
        // 如果未找到sought, 返回一个指向此set的指针。
        static shared_ptr<set<line_no>> nodata (new set<line_no>);
        auto loc = sp_dictionary.find(word);
    
        if (loc == sp_dictionary.end()) {
            return QueryResult(word, nodata, sp_text);
        }
        else {
            return QueryResult(word, loc->second, sp_text);
        }
    }
    
    ostream& print(ostream& os, const QueryResult& qr)
    {
        os << qr.sought << " occurs " << qr.lines->size() << " times." << endl;
    
        for (auto i : *qr.lines) {
            os << "	(line " << i+1 << qr.file->at(i) << endl;
        }
        return os;
    }
    
    void runQueries (ifstream &infile)
    {
        TextQuery tq (infile);
    
        while (true) {
            cout << "Enter word to look for, or q to quit: ";
            string s;
    
            if (!(cin >> s) || s == "q") break;
                print (cout, tq.query(s)) << endl;
        }
    }
    
    int main()
    {
        ifstream ifs ("C:/Users/tutu/Documents/code/cpp_primer/ch12/textQuery.cpp");
        runQueries(ifs);
        return 0;
    }
    

    这个程序未过滤符号,因此查找的时候如果前后有标点符号,也会算另一个单词。如本文件中的text,本应有两处,但第二处插入到map中是text)),因此实际只能找到一个text。过滤标点符号的版本如12.28题。

    12.31 如果用vector代替set保存行号,会有什么差别?哪种方法更好?为什么?

    set更好,因为vector保存不会排序,查找结果便不能按照行号的由小到大顺序显示了。

    12.32 重写 TextQuery和QueryResult类,用StrBlob类代替vector 保存输入文件。

    如下题 ~

    12.33 在第15章中我们将扩展查询系统,在QueryResult类中将会需要一些额外的成员。添加名为begin和end的成员,返回一个迭代器,指向一个给定查询返回行号的set中的位置。再添加一个名为get_file的成员,返回一个shared_ptr,指向QueryResult对象中的文件。

    class QueryResult;
    class TextQuery
    {
    public:
     //   using line_no = std::vector<std::string>::size_type;
        TextQuery(std::ifstream& ifs);
        QueryResult query (const std::string& word) const;
    
    private:
        StrBlob sp_text;
        // 每个单词到它所出现的行号的映射
        std::map<std::string, std::shared_ptr<std::set<StrBlob::size_type>>> sp_dictionary;
    };
    
    class QueryResult
    {
    public:
         friend std::ostream& print (std::ostream&, const QueryResult&);
    public:
        std::set<StrBlob::size_type>::iterator begin() const { return lines->begin(); }
        std::set<StrBlob::size_type>::iterator end() const { return lines->end(); }
        std::shared_ptr<StrBlob> getFile() const { return make_shared<StrBlob>(file); }
        QueryResult(const std::string& s,
                    std::shared_ptr<std::set<StrBlob::size_type>> sp_set,
                    StrBlob sb):
                sought (s), lines (sp_set), file (sb) {}
    
    private:
        std::string sought;     // 要查找的单词
         // 出现的行号
        std::shared_ptr<std::set<StrBlob::size_type>> lines;
       // 输入文件
        StrBlob file;
    };
    
    std::ostream& print (std::ostream&, const QueryResult&);
    
    .cpp文件
    #include "textQuery_StrBlob.h"
    using namespace std;
    
    TextQuery::TextQuery(std::ifstream& ifs)
    {
        string text;
        StrBlob::size_type n = 0;
        while (getline(ifs, text)) {
            sp_text.push_back(text);
            n = sp_text.size() - 1;    // 当前行号
            istringstream line (text);
            string word;
            while (line >> word) {
                auto &lines = sp_dictionary[word];
    
                if (!lines) {
                    lines.reset (new std::set<StrBlob::size_type>);
                }
                lines->insert(n);
            }
        }
    }
    
    QueryResult TextQuery::query(const std::string& word) const
    {
        // 如果未找到sought, 返回一个指向此set的指针。
        static shared_ptr<set<StrBlob::size_type>> nodata (new set<StrBlob::size_type>);
        auto loc = sp_dictionary.find(word);
    
        if (loc == sp_dictionary.end()) {
            return QueryResult(word, nodata, sp_text);
        }
        else {
            return QueryResult(word, loc->second, sp_text);
        }
    }
    
    ostream& print(ostream& os, const QueryResult& qr)
    {
        os << qr.sought << " occurs " << qr.lines->size() << " times." << endl;
    
        for (auto iter = qr.begin(); iter != qr.end(); ++ iter) {
            ConstStrBlobPtr p (*qr.getFile(), *iter);
            os << "	(line " << *iter+1 << ") " << p.deref() << endl;
        }
        return os;
    }
    
    void runQueries (ifstream &infile)
    {
        TextQuery tq (infile);
    
        while (true) {
            cout << "Enter word to look for, or q to quit: ";
            string s;
    
            if (!(cin >> s) || s == "q") break;
                print (cout, tq.query(s)) << endl;
        }
    }
    
    int main()
    {
        ifstream ifs ("C:/Users/tutu/Documents/code/cpp_primer/ch12/textQuery.cpp");
        runQueries(ifs);
        return 0;
    }
    
  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/songshuguiyu/p/9598196.html
Copyright © 2011-2022 走看看