C++ Primer第5版 第十二章课后练习答案

练习12.1

b1和b2各包含四个元素(如果想使用C++ PRIMER源码,请在main函数所在cpp文件中加入#define LIST_INIT开启对应功能)

练习12.2

inline
const std::string& StrBlob::front()
{
    check(0, "front on empty StrBlob");
    return data->front();
}

inline
const std::string& StrBlob::back() {
    check(0, "back on empty StrBlob");
    return data->back();
}

练习12.3

不需要,因为push_back和pop_back本身就是对于容器进行修改

练习12.4

因为只要保证上述需要调用check函数的函数能检查容器中是否有元素即可。

练习12.5

explicit会抑制构造函数参数的隐式类型转换

优点

  编译器不会在自动转换中使用此构造函数。

  我们可以清楚地意识到我们用过哪个类。

缺点

  我们总是使用构造函数来构造一个临时的StrBlob对象。

  不能将初始化的复制形式与显式构造函数一起使用。不容易使用。

练习12.6

std::vector<int>* dynamic_vector_generator();

void dynamic_vector_processor(std::vector<int>* ptr_v);

void dynamic_vector_printer(std::vector<int>* ptr_v);

int main(int argc, char* argv[])
{
    vector<int>* pv = dynamic_vector_generator();
    dynamic_vector_processor(pv);
    dynamic_vector_printer(pv);
}

std::vector<int>* dynamic_vector_generator() {
    vector<int>* pv = new vector<int>();
    return pv;
}

void dynamic_vector_processor(std::vector<int>* ptr_v) {
    int i;
    while (cin >> i) { ptr_v->emplace_back(i); }
}

void dynamic_vector_printer(std::vector<int>* ptr_v) {
    for (const auto& i : *ptr_v) { cout << i << " "; }
}

练习12.7

std::shared_ptr<std::vector<int>> dynamic_vector_generator();

void dynamic_vector_processor(std::shared_ptr<std::vector<int>>);

void dynamic_vector_printer(std::shared_ptr<std::vector<int>>);

int main(int argc, char* argv[])
{
    auto pv = dynamic_vector_generator();
    dynamic_vector_processor(pv);
    dynamic_vector_printer(pv);
}

std::shared_ptr<std::vector<int>> dynamic_vector_generator() {
    return std::make_shared<std::vector<int>>();
}

void dynamic_vector_processor(std::shared_ptr<std::vector<int>> ptr_v) {
    int i;
    while (cin >> i) { ptr_v->emplace_back(i); }
}

void dynamic_vector_printer(std::shared_ptr<std::vector<int>> ptr_v) {
    for (const auto& i : *ptr_v) { cout << i << " "; }
}

练习12.8

有,返回p的时候会被自动转换成bool值,因为没有机会释放p的内存,会造成内存泄漏

练习12.9

r指向q会发生内存泄漏,因为r原本指向的内存没机会释放

r2指向q2则不会,r2原本指向的内存区引用数会减一,当引用数为零时会自动释放该内存

练习12.10

正确,process拷贝p会递增它的引用计数变为二;离开process时临时shared_ptr会被销毁让引用计数减一变为一

练习12.11

把另一个临时智能指针绑定到get返回的内置指针上,当临时指针离开作用域时会销毁该临时指针导致指向的内存被释放,此时p成为了空悬指针

练习12.12

(a)合法,process拷贝sp会递增它的引用计数变为二;离开process时临时shared_ptr会被销毁让引用计数减一变为一

(b)不合法,因为new int()是一个普通指针不是一个智能指针

(c)不合法,因为p是一个普通指针不是一个智能指针

(d)合法,但是离开process作用域时内存会被释放

练习12.13

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

练习12.14

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) : des(ip, port), status(1) {}
    destination des;
    int status;
};

connection connect(std::shared_ptr <destination> des) {
    std::shared_ptr<connection> p(new connection(des->m_ip, des->m_port));
    return *p;
}

void disconnect(connection* p) {
    cout << "ip:" << p->des.m_ip << " " << "port:" << p->des.m_port << " " << "status" << p->status << endl;
}

void end_connection(connection* p) {
    disconnect(p);
}

void f(std::shared_ptr <destination> d)
{
    connection c = connect(d);
    std::shared_ptr<connection> p(&c, end_connection);
}

练习12.15

void f(std::shared_ptr <destination> d)
{
    connection c = connect(d);
    std::shared_ptr<connection> p(&c, [](connection* p) { disconnect(p); });
}

练习12.16

int main(int argc, char* argv[])
{
    std::unique_ptr<string> p1(new string("Stegosaurus"));
    std::unique_ptr<string> p2(p1);
    std::unique_ptr<string> p3 = p1;
}

error C2280: “std::unique_ptr<std::string,std::default_delete<std::string>>::unique_ptr(const std::unique_ptr<std::string,std::default_delete<std::string>> &)”: 尝试引用已删除的函数
note: 参见“std::unique_ptr<std::string,std::default_delete<std::string>>::unique_ptr”的声明
note: “std::unique_ptr<std::string,std::default_delete<std::string>>::unique_ptr(const std::unique_ptr<std::string,std::default_delete<std::string>> &)”: 已隐式删除函数

练习12.17

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

练习12.18

因为如果shared_ptr要实现这个功能需要先获取共享对象的智能指针然后再一个个放弃控制权,但是这很难实现

练习12.19

/*
 * This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
 * Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
 * copyright and warranty notices given in that book:
 * 
 * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
 * 
 * 
 * "The authors and publisher have taken care in the preparation of this book,
 * but make no expressed or implied warranty of any kind and assume no
 * responsibility for errors or omissions. No liability is assumed for
 * incidental or consequential damages in connection with or arising out of the
 * use of the information or programs contained herein."
 * 
 * Permission is granted for this code to be used for educational purposes in
 * association with the book, given proper citation if and when posted or
 * reproduced. Any commercial use of this code requires the explicit written
 * permission of the publisher, Addison-Wesley Professional, a division of
 * Pearson Education, Inc. Send your request for permission, stating clearly
 * what code you would like to use, and in what specific way, to the following
 * address: 
 * 
 *     Pearson Education, Inc.
 *     Rights and Permissions Department
 *     One Lake Street
 *     Upper Saddle River, NJ  07458
 *     Fax: (201) 236-3290
*/
#ifndef STRBLOB_H
#define STRBLOB_H
#define LIST_INIT

#include <vector>
#include <string>
#include <memory>
#include <stdexcept>

#ifdef LIST_INIT
#include <initializer_list>
#endif

// forward declaration needed for friend declaration in StrBlob
class StrBlobPtr;

class StrBlob {
    friend class StrBlobPtr;
public:
    typedef std::vector<std::string>::size_type size_type;

    // constructors
    StrBlob() : data(std::make_shared<std::vector<std::string>>()) { }
#ifdef LIST_INIT
    StrBlob(std::initializer_list<std::string> il);
#else
    StrBlob(std::string *, std::string*);  
#endif

    // size operations
    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
    const std::string& front();
    const std::string& back();

    // interface to StrBlobPtr
    StrBlobPtr begin();  // can't be defined until StrBlobPtr is
    StrBlobPtr end();
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;
};

// constructor
#ifdef LIST_INIT
inline
StrBlob::StrBlob(std::initializer_list<std::string> il): 
              data(std::make_shared<std::vector<std::string>>(il)) { }
#else
inline
StrBlob::StrBlob(std::string *b, std::string *e):
              data(std::make_shared<std::vector<std::string>>(b,e)) { }
#endif

// StrBlobPtr throws an exception on attempts to access a nonexistent element 
class StrBlobPtr {
    friend bool eq(const StrBlobPtr&, const StrBlobPtr&);
public:
    StrBlobPtr(): curr(0) { }
    StrBlobPtr(StrBlob &a, size_t sz = 0): wptr(a.data), curr(sz) { }

    std::string& deref() const;
    StrBlobPtr& incr();       // prefix version
    StrBlobPtr& decr();       // prefix version
private:
    // check returns a shared_ptr to the vector if the check succeeds
    std::shared_ptr<std::vector<std::string>> 
        check(std::size_t, const std::string&) const;

    // store a weak_ptr, which means the underlying vector might be destroyed
    std::weak_ptr<std::vector<std::string>> wptr;  
    std::size_t curr;      // current position within the array
};

inline
std::string& StrBlobPtr::deref() const
{
    auto p = check(curr, "dereference past end"); 
    return (*p)[curr];  // (*p) is the vector to which this object points
}

inline
std::shared_ptr<std::vector<std::string>> 
StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
    auto ret = wptr.lock();   // is the vector still around?
    if (!ret)
        throw std::runtime_error("unbound StrBlobPtr");

    if (i >= ret->size()) 
        throw std::out_of_range(msg);
    return ret; // otherwise, return a shared_ptr to the vector
}

// prefix: return a reference to the incremented object
inline
StrBlobPtr& StrBlobPtr::incr()
{
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment past end of StrBlobPtr");
    ++curr;       // advance the current state
    return *this;
}

inline
StrBlobPtr& StrBlobPtr::decr()
{
    // if curr is zero, decrementing it will yield an invalid subscript
    --curr;       // move the current state back one element}
    check(-1, "decrement past begin of StrBlobPtr");
    return *this;
}

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

inline
const std::string& StrBlob::front()
{
    check(0, "front on empty StrBlob");
    return data->front();
}

inline
const std::string& StrBlob::back() {
    check(0, "back on empty StrBlob");
    return data->back();
}





// begin and end members for StrBlob
inline
StrBlobPtr
StrBlob::begin() 
{
    return StrBlobPtr(*this);
}

inline
StrBlobPtr
StrBlob::end() 
{
    auto ret = StrBlobPtr(*this, data->size());
    return ret; 
}

// named equality operators for StrBlobPtr
inline
bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
    auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
    // if the underlying vector is the same 
    if (l == r) 
        // then they're equal if they're both null or 
        // if they point to the same element
        return (!r || lhs.curr == rhs.curr);
    else
        return false; // if they point to difference vectors, they're not equal
}

inline
bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
    return !eq(lhs, rhs); 
}
#endif

练习12.20

int main(int argc, char* argv[])
{
    ifstream ifs;
    string str;
    StrBlob sb;
    ifs.open(argv[1]);
    while (getline(ifs, str)) {
        sb.push_back(str);
    }   
    for (StrBlobPtr sbp(sb); !eq(sbp,sb.end()); sbp.incr()) {
        cout << sbp.deref() << endl;
    };
}

练习12.21

第一个版本好,第二个版本看似减少了一行代码但是可读性降低了

练习12.22

#include "StrBlob.h"

std::string& ConstStrBlobPtr::deref() const
{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];  // (*p) is the vector to which this object points
}

ConstStrBlobPtr& ConstStrBlobPtr::incr()
{
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment past end of StrBlobPtr");
    ++curr;       // advance the current state
    return *this;
}

ConstStrBlobPtr& ConstStrBlobPtr::decr()
{
    // if curr is zero, decrementing it will yield an invalid subscript
    --curr;       // move the current state back one element}
    check(-1, "decrement past begin of StrBlobPtr");
    return *this;
}

std::shared_ptr<std::vector<std::string>> ConstStrBlobPtr::check(std::size_t i, const std::string&msg) const
{
    auto ret = wptr.lock();   // is the vector still around?
    if (!ret)
        throw std::runtime_error("unbound StrBlobPtr");

    if (i >= ret->size())
        throw std::out_of_range(msg);
    return ret; // otherwise, return a shared_ptr to the vector
}
int main(int argc, char* argv[])
{
    ifstream ifs;
    string str;
    StrBlob sb;
    ifs.open(argv[1]);
    while (getline(ifs, str)) {
        sb.push_back(str);
    }   
    for (ConstStrBlobPtr sbp(sb); neq(sbp,sb.cend()); sbp.incr()) {
        cout << sbp.deref() << endl;
    };
}

练习12.23

连接两个字符串字面常量

int main(int argc, char* argv[])
{
    const char* str1 = "123";
    const char* str2 = "456";
    char* p = new char[strlen(str1)+strlen(str2)+1]{ 0 };

    strcat_s(p, strlen(str1) + 1, str1);
    strcat_s(p, strlen(str1) + strlen(str2) + 1, str2);
    for (char* pp = p; pp != p + strlen(str1) + strlen(str2); ++pp)
        std::cout << *pp;

    return 0;
}

连接两个标准库string对象

int main(int argc, char* argv[])
{
    string str1 = "123";
    string str2 = "456";
    string* p = new string;
    *p += (str1 + str2);
    std::cout << *p;
    return 0;
}

练习12.24

int main(int argc, char* argv[])
{
    string str;
    cin >> str;
    char* chars = new char[strlen(str.c_str()) + 1];
    memset(chars, 0, strlen(str.c_str()) + 1);
    strcpy_s(chars, strlen(str.c_str()) + 1, str.c_str());
    cout << chars;
    delete[] chars;
    return 0;
}

练习12.25

int main(int argc, char* argv[])
{
    int* pa = new int[10];
    delete[]pa;
    return 0;
}

练习12.26

int main(int argc, char* argv[])
{
    allocator<int> pa;
    auto p=pa.allocate(10);
    pa.deallocate(p, 10);
    return 0;
}

练习12.27

#include <fstream>
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
#include <map>
using std::map;
using std::multimap;
#include <set>
using std::multiset;
using std::set;
#include <sstream>
using std::istringstream;
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_map;
#include <vector>
using std::vector;
#ifndef TEXTQUERT_H_
#define TEXTQUERT_H_
class QueryResult;
class TextQuery
{
    friend class QueryResult;
public:
    TextQuery() :text(std::make_shared<vector<string>>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>()) {}
    TextQuery(ifstream& ifs);
    QueryResult query(string s);
    ~TextQuery();

private:
    std::shared_ptr<vector<string>>text;
    std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words;
};

class QueryResult
{
    friend ostream& print(ostream& os, const QueryResult qr);
public:
    QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<vector<string>> i) :word(w), nos(n), inputs(i) {}
    ~QueryResult();

private:
    string word;
    std::shared_ptr<set<size_t>> nos;
    std::shared_ptr<vector<string>> inputs;
};

QueryResult::~QueryResult()
{
}

inline TextQuery::TextQuery(ifstream& ifs) : text(std::make_shared<vector<string>>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>())
{
    size_t size;
    string str, word;
    istringstream iss;
    if (ifs) {
        while (getline(ifs, str))
        {
            text->emplace_back(str);
        }
        size = text->size();
        for (auto it = 0; it < size;++it) {
            iss.clear();
            iss.str((*text)[it]);
            while (iss >> word) {
                auto& nos = (*query_words)[word];
                if (!nos) nos.reset(new std::set<size_t>);
                nos->insert(it);
            }
        }
    }
}

inline QueryResult TextQuery::query(string s)
{
    static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
    auto found = query_words->find(s);
    if (found == query_words->end()) {
        cout << s + " is not in the text" << endl;
        return QueryResult(s, nodate, text);
    }
    else
        return QueryResult(s, found->second, text);
}

TextQuery::~TextQuery()
{
}

ostream& print(ostream& os, const QueryResult qr) {
    os << qr.word << " occurs " << qr.nos->size() << " times" << endl;
    for (auto i : *qr.nos)
        os << "	(line " << i + 1 << ") " << qr.inputs->at(i) << std::endl;
    return os;
}
#endif // !TEXTQUERT_H_
void runQueries(std::ifstream& infile)
{
    TextQuery tq(infile);
    while (true) {
        std::cout << "enter word to look for, or q to quit: ";
        string s;
        if (!(std::cin >> s) || s == "q") break;
        print(std::cout, tq.query(s)) << std::endl;
    }
}

int main(int argc, char* argv[])
{
    std::ifstream file(argv[1]);
    runQueries(file);
    return 0;
}

练习12.28

int main(int argc, char* argv[])
{
    size_t size;
    string str, word;
    istringstream iss;
    std::ifstream file(argv[1]);
    vector<string>text;
    map<string, set<size_t>> query_words;
    if (file) {
        while (getline(file, str))
        {
            text.emplace_back(str);
        }
        size = text.size();
        for (auto it = 0; it < size; ++it) {
            iss.clear();
            iss.str(text[it]);
            while (iss >> word) {
                auto& nos = query_words[word];
                nos.insert(it);
            }
        }
    }
    while (true) {
        std::cout << "enter word to look for, or q to quit: ";
        string s;
        if (!(std::cin >> s) || s == "q") break;
        static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
        auto found = query_words.find(s);
        if (found == query_words.end()) {
            cout << s + " is not in the text" << endl;
            cout << s << " occurs " << found->second.size() << " times" << endl;
            for (auto i : found->second)
                cout << "	(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
        else {
            cout << s << " occurs " << found->second.size() << " times" << endl;
            for (auto i : found->second)
                cout << "	(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
    }
    return 0;
}

练习12.29

int main(int argc, char* argv[])
{
    size_t size;
    string str, word;
    istringstream iss;
    std::ifstream file(argv[1]);
    vector<string>text;
    map<string, set<size_t>> query_words;
    if (file) {
        getline(file, str);
        do{
            text.emplace_back(str);
        } while (getline(file, str));
        size = text.size();
        for (auto it = 0; it < size; ++it) {
            iss.clear();
            iss.str(text[it]);
            iss >> word;
            do{
                auto& nos = query_words[word];
                nos.insert(it);
            } while (iss >> word);
        }
    }
    do{
        std::cout << "enter word to look for, or q to quit: ";
        string s;
        if (!(std::cin >> s) || s == "q") break;
        static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
        auto found = query_words.find(s);
        if (found == query_words.end()) {
            cout << s + " is not in the text" << endl;
            cout << s << " occurs " << found->second.size() << " times" << endl;
            for (auto i : found->second)
                cout << "	(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
        else {
            cout << s << " occurs " << found->second.size() << " times" << endl;
            for (auto i : found->second)
                cout << "	(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
    } while (true);
    return 0;
}

我更倾向于用while而不是do while,因为如果循环的第一步就要判断那么do while不是一个很合适的写法

练习12.30

#include <fstream>
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
#include <map>
using std::map;
using std::multimap;
#include <set>
using std::multiset;
using std::set;
#include <sstream>
using std::istringstream;
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_map;
#include <vector>
using std::vector;
#ifndef TEXTQUERT_H_
#define TEXTQUERT_H_
class QueryResult;
class TextQuery
{
    friend class QueryResult;
public:
    TextQuery() :text(std::make_shared<vector<string>>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>()) {}
    TextQuery(ifstream& ifs);
    QueryResult query(string s);
    ~TextQuery();

private:
    std::shared_ptr<vector<string>>text;
    std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words;
};

class QueryResult
{
    friend ostream& print(ostream& os, const QueryResult qr);
public:
    QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<vector<string>> i) :word(w), nos(n), inputs(i) {}
    ~QueryResult();

private:
    string word;
    std::shared_ptr<set<size_t>> nos;
    std::shared_ptr<vector<string>> inputs;
};

QueryResult::~QueryResult()
{
}

inline TextQuery::TextQuery(ifstream& ifs) : text(std::make_shared<vector<string>>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>())
{
    size_t size;
    string str, word;
    istringstream iss;
    if (ifs) {
        while (getline(ifs, str))
        {
            text->emplace_back(str);
        }
        size = text->size();
        for (auto it = 0; it < size;++it) {
            iss.clear();
            iss.str((*text)[it]);
            while (iss >> word) {
                auto& nos = (*query_words)[word];
                if (!nos) nos.reset(new std::set<size_t>);
                nos->insert(it);
            }
        }
    }
}

inline QueryResult TextQuery::query(string s)
{
    static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
    auto found = query_words->find(s);
    if (found == query_words->end()) {
        cout << s + " is not in the text" << endl;
        return QueryResult(s, nodate, text);
    }
    else
        return QueryResult(s, found->second, text);
}

TextQuery::~TextQuery()
{
}

ostream& print(ostream& os, const QueryResult qr) {
    os << qr.word << " occurs " << qr.nos->size() << " times" << endl;
    for (auto i : *qr.nos)
        os << "	(line " << i + 1 << ") " << qr.inputs->at(i) << std::endl;
    return os;
}
#endif // !TEXTQUERT_H_

练习12.31

如果用vector代替set,查询速度就会从O(1)降为O(logN),如果是只需要遍历输出单词出现的所有行号,那么使用vector会更节约空间,否则使用set可以满足更多需求

练习12.32

#include <fstream>
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
#include <map>
using std::map;
using std::multimap;
#include <set>
using std::multiset;
using std::set;
#include <sstream>
using std::istringstream;
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_map;
#include <vector>
using std::vector;
#ifndef TEXTQUERT_H_
#define TEXTQUERT_H_
class QueryResult;
class TextQuery
{
    friend class QueryResult;
public:
    TextQuery() :text(std::make_shared <StrBlob>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>()) {}
    TextQuery(ifstream& ifs);
    QueryResult query(string s);
    ~TextQuery();

private:
    std::shared_ptr <StrBlob> text;
    std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words;
};

class QueryResult
{
    friend ostream& print(ostream& os, const QueryResult qr);
public:
    QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<StrBlob> i) :word(w), nos(n), inputs(i) {}
    ~QueryResult();

private:
    string word;
    std::shared_ptr<set<size_t>> nos;
    std::shared_ptr<StrBlob> inputs;
};

QueryResult::~QueryResult()
{
}

inline TextQuery::TextQuery(ifstream& ifs) : text(std::make_shared<StrBlob>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>())
{
    size_t size;
    string str, word;
    istringstream iss;
    if (ifs) {
        for (string line;getline(ifs, str);++size)
        {
            text->push_back(str);
            iss.str(str);
            size = text->size();
            for (string text, word; iss >> text; word.clear()) {
                std::remove_copy_if(text.begin(), text.end(),
                    std::back_inserter(word), ispunct);
                // use reference avoid count of shared_ptr add.
                auto& nos = (*query_words)[word];
                if (!nos) nos.reset(new std::set<StrBlob::size_type>);
                nos->insert(size);
            }
        }
    }
}

inline QueryResult TextQuery::query(string s)
{
    static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
    auto found = query_words->find(s);
    if (found == query_words->end()) {
        cout << s + " is not in the text" << endl;
        return QueryResult(s, nodate, text);
    }
    else
        return QueryResult(s, found->second, text);
}

TextQuery::~TextQuery()
{
}

ostream& print(ostream& os, const QueryResult qr) {
    os << qr.word << " occurs " << qr.nos->size() << " times" << endl;
    for (auto i : *qr.nos) {
        ConstStrBlobPtr p(*qr.inputs, i);
        os << "	(line " << i + 1 << ") " << p.deref() << std::endl;
    }    
    return os;
}
#endif // !TEXTQUERT_H_

练习12.33

#include <fstream>
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
#include <map>
using std::map;
using std::multimap;
#include <set>
using std::multiset;
using std::set;
#include <sstream>
using std::istringstream;
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_map;
#include <vector>
using std::vector;
#ifndef TEXTQUERT_H_
#define TEXTQUERT_H_
class QueryResult;
class TextQuery
{
    friend class QueryResult;
public:
    TextQuery() :text(std::make_shared <StrBlob>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>()) {}
    TextQuery(ifstream& ifs);
    QueryResult query(string s);
    ~TextQuery();

private:
    std::shared_ptr <StrBlob> text;
    std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words;
};

class QueryResult
{
public:
    friend ostream& print(ostream& os, const QueryResult qr);
    using QueryIterator = set<size_t>::iterator;
public:
    QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<StrBlob> i) :word(w), nos(n), inputs(i) {}
    ~QueryResult();
    QueryIterator begin() { return nos->begin(); }
    QueryIterator end() { return nos->end(); }
    std::shared_ptr <StrBlob> get_file() { return inputs; }
private:
    string word;
    std::shared_ptr<set<size_t>> nos;
    std::shared_ptr<StrBlob> inputs;
};

QueryResult::~QueryResult()
{
}

inline TextQuery::TextQuery(ifstream& ifs) : text(std::make_shared<StrBlob>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>())
{
    size_t size;
    string str, word;
    istringstream iss;
    if (ifs) {
        for (string line;getline(ifs, str);++size)
        {
            text->push_back(str);
            iss.str(str);
            size = text->size();
            for (string text, word; iss >> text; word.clear()) {
                std::remove_copy_if(text.begin(), text.end(),
                    std::back_inserter(word), ispunct);
                // use reference avoid count of shared_ptr add.
                auto& nos = (*query_words)[word];
                if (!nos) nos.reset(new std::set<StrBlob::size_type>);
                nos->insert(size);
            }
        }
    }
}

inline QueryResult TextQuery::query(string s)
{
    static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>);
    auto found = query_words->find(s);
    if (found == query_words->end()) {
        cout << s + " is not in the text" << endl;
        return QueryResult(s, nodate, text);
    }
    else
        return QueryResult(s, found->second, text);
}

TextQuery::~TextQuery()
{
}

ostream& print(ostream& os, const QueryResult qr) {
    os << qr.word << " occurs " << qr.nos->size() << " times" << endl;
    for (auto i : *qr.nos) {
        ConstStrBlobPtr p(*qr.inputs, i);
        os << "	(line " << i + 1 << ") " << p.deref() << std::endl;
    }    
    return os;
}
#endif // !TEXTQUERT_H_
原文地址:https://www.cnblogs.com/GodZhuan/p/13977921.html