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;
    }
    
  • 相关阅读:
    泛型技巧系列:如何提供类型参数之间的转换
    一些支离破碎的泛型反射技巧
    泛型技巧系列:类型字典和Type Traits
    Excel开发:简化工作表中选定区域的操作。
    趣味程序:打印自己代码的程序
    VBF BETA 1.5 发布了
    .NET 2.0 CER学习笔记
    随笔乱入,开心就好
    Cocos2dx for WindowsPhone:开发一个打地鼠游戏(下)
    跨平台网络游戏趋势和优势
  • 原文地址:https://www.cnblogs.com/songshuguiyu/p/9598196.html
Copyright © 2011-2022 走看看