C++ Primer 5th Edition chapter 12 after class practice answers

Exercise 12.1

b1 and b2 contain four elements respectively (if you want to use the C++ PRIMER source code, please add #define LIST_INIT to the cpp file where the main function is located to enable the corresponding function)

 

Exercise 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();
}

 

Exercise 12.3

No, because push_back and pop_back itself is to modify the container

 

Exercise 12.4

As long as the above functions that need to call the check function can check whether there are elements in the container.

 

Exercise 12.5

explicit suppresses the implicit type conversion of constructor parameters

advantage

The compiler will not use this constructor in automatic conversion.

We can clearly realize which class we have used.

shortcoming

We always use constructors to construct a temporary StrBlob object.

An initialized copy form cannot be used with an explicit constructor. Not easy to use.

 

Exercise 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 << " "; }
}

 

Exercise 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 << " "; }
}

 

Exercise 12.8

Yes, when p is returned, it will be automatically converted to bool value, because there is no chance to free the memory of P, which will cause memory leakage

 

Exercise 12.9

Memory leakage occurs when r points to q, because the memory originally pointed to by r has no chance to be released

If r2 points to q2, it will not. The number of memory area references originally pointed to by r2 will be reduced by one. When the number of references is zero, the memory will be automatically released

 

Exercise 12.10

Correct, process copy p will be incremented, and its reference count will become two; Temporary shared when leaving process_ The PTR is destroyed and the reference count is reduced from one to one

 

Exercise 12.11

Bind another temporary smart pointer to the built-in pointer returned by get. When the temporary pointer leaves the scope, the temporary pointer will be destroyed, resulting in the release of the memory pointed to. At this time, p becomes an empty pointer

 

Exercise 12.12

(a) Legal, the process copy sp will be incremented, and its reference count will become two; Temporary shared when leaving process_ The PTR is destroyed and the reference count is reduced from one to one

(b) Illegal, because new int() is a normal pointer, not a smart pointer

(c) Illegal, because p is a normal pointer, not a smart pointer

(d) Legal, but the memory will be released when leaving the process scope

 

Exercise 12.13

Use sp to initialize p, p and sp point to the same block of memory. After delete p, this memory will be released, and sp will also be released.

 

Exercise 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);
}

 

Exercise 12.15

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

 

Exercise 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 > > &)": try to reference the deleted function
note: see the statement of "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 > > &)": the function has been implicitly deleted

 

Exercise 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);            // wrongful, unique_ptr Can only be bound to new On the pointer returned.
    IntP p1(pi);            // There is no error during compilation, and it can run correctly on my compiler. However, it is not recommended because smart pointers are used unique_ptr,The compiler calls when it detects that the pointer is out of range delete To release, but pi Not again new Assigned, so it cannot be used delete To release, so when p1 When it is illegal, the operating system will throw an error, resulting in a runtime error.
    IntP p2(pi2);           // Can be used, but it is possible to generate a null pointer at run time pi2,Because at runtime, p2 The indicated space may be released, pi2 It becomes a dangling pointer.
    IntP p3(&ix);           // with b,The compiler will not report an error, but it cannot be used delete Release.
    IntP p4(new int(2048)); // legitimate
    IntP p5(p2.get());      // Illegal use get Initialize a smart pointer, p2 and p5 Point to the same memory. When the pointer is illegal, the smart pointer will automatically delete,This memory will be released.
}

 

Exercise 12.18

Because if shared_ To realize this function, PTR needs to obtain the smart pointer of the shared object first, and then give up control one by one, but it is difficult to achieve

 

Exercise 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

 

 

Exercise 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;
    };
}

 

Exercise 12.21

The first version is good. The second version seems to reduce one line of code, but the readability is reduced

 

Exercise 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;
    };
}

 

Exercise 12.23

Concatenate two string literal constants

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;
}

Connecting two standard library string objects

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

 

Exercise 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;
}

 

Exercise 12.25

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

 

Exercise 12.26

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

 

Exercise 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 << "\t(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;
}

 

Exercise 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 << "\t(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
        else {
            cout << s << " occurs " << found->second.size() << " times" << endl;
            for (auto i : found->second)
                cout << "\t(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
    }
    return 0;
}

 

Exercise 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 << "\t(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
        else {
            cout << s << " occurs " << found->second.size() << " times" << endl;
            for (auto i : found->second)
                cout << "\t(line " << i + 1 << ") " << text.at(i) << std::endl;
        }
    } while (true);
    return 0;
}

I prefer to use while instead of do while, because if the first step of the loop needs to be judged, do while is not a very appropriate way to write it

 

Exercise 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 << "\t(line " << i + 1 << ") " << qr.inputs->at(i) << std::endl;
    return os;
}
#endif // !TEXTQUERT_H_

 

Exercise 12.31

If you use vector instead of set, the query speed will be reduced from O(1) to O(logN). If you only need to traverse all the line numbers of the output word, using vector will save more space. Otherwise, using set can meet more requirements

 

Exercise 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 << "\t(line " << i + 1 << ") " << p.deref() << std::endl;
    }    
    return os;
}
#endif // !TEXTQUERT_H_

 

Exercise 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 << "\t(line " << i + 1 << ") " << p.deref() << std::endl;
    }    
    return os;
}
#endif // !TEXTQUERT_H_

 

Posted by cafegirl on Sat, 07 May 2022 09:49:05 +0300