cppPrimer学习12th

cppPrimer学习12th

12.1

b1 有4个
b2 元素销毁了

12.2

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

#include "../include/include.h"
#include <initializer_list>
#include <memory>
#include <exception>
class StrBlob
{

public:
    typedef vector<string>::size_type size_type;
    () : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}
    size_type size() const
    {
        return data->size();
    }
    bool empty() const
    {
        return data->empty();
    }

    void push_back(const string &s)
    {
        data->push_back(s);
    }
    void pop_back();

    string &front();
    string &back();
    const string &front() const;
    const string &back() const;

    ~StrBlob();

private:
    shared_ptr<vector<string>> data;
    void check(size_type i, const string &message) const
    {
        if (i >= data->size())
            throw std::out_of_range(message);
    }
};

StrBlob::~StrBlob()
{
}

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, "pop_back on empty StrBlob");
    data->pop_back();
}

int main(int argc, const char **argv)
{

    StrBlob csb{"1", "2", "3"};
    StrBlob sb{"A1", "A2", "A3"};

    std::cout << csb.front() << " " << csb.back() << std::endl;
    sb.back() = "change";
    std::cout << sb.front() << " " << sb.back() << std::endl;
    while (1)
        ;
    return 0;
}

12.3

不需要,因为这个操作本身会改变data指向的内容

12.4

size>=0  size_type 是unsigned的

12.5

如果有 initialize_list explicit的构造函数  那么就不能使用隐式转换了

没有的优点:
在需要 StrBlob的地方可以自动进行列表转换,比如使用一个类 StrBlob=("1","2");

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

反之
编译器不会在自动转换中使用此构造函数,我们可以清楚地知道我们使用了哪个类

12.6

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

using namespace std;

vector<int> *get_vector_int_pt(void)
{
    return new vector<int>();
}

vector<int> *put_vector_int_pt(vector<int> *pt)
{
    int num;
    while (cin >> num)
        pt->push_back(num);

    return pt;
}

void show_vector_int_pt(vector<int> *pt)
{
    for (int a : *pt)
        cout << a << " ";
    cout << endl;
}

int main(int argc, char const *argv[])
{
    vector<int> *t = get_vector_int_pt();
    put_vector_int_pt(t);
    show_vector_int_pt(t);
    delete t;

    while (1)
        ;
    return 0;
}

12.7

/*
12.7 使用 shared_ptr
编写函数,返回一个动态分配的int的vector。将此vector传递给另一个函数。这个函数读取标准输入,
将读入的值保存在vector中。再将vector传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector
*/
#include <vector>
#include <memory>
#include <iostream>

using namespace std;

shared_ptr<vector<int>> get_vector_int_pt(void)
{
    return make_shared<vector<int>>();
}

shared_ptr<vector<int>> put_vector_int_pt(shared_ptr<vector<int>> pt)
{
    int num;
    while (cin >> num)
        pt->push_back(num);

    return pt;
}

void show_vector_int_pt(shared_ptr<vector<int>> pt)
{
    for (int a : *pt)
        cout << a << " ";
    cout << endl;
}

int main(int argc, char const *argv[])
{
    shared_ptr<vector<int>> t = get_vector_int_pt();
    put_vector_int_pt(t);
    show_vector_int_pt(t);

    while (1)
        ;
    return 0;
}

12.8

p 是一个指针,转换为bool, 但是p原来的内存永远不会释放了

12.9

r和q指向42,但是r原来的内存无法释放,同时两个指针指向同一个地方
可能释放了一个指针后,另一个没释放的指向已经释放的内存,也就是空悬指针问题

r2指向q2,同时原来r2 内存释放

12.10

void process(shared_ptr ptr)  // 注意这里是值拷贝,也就是引用+1
{
    // 使用ptr
}
//离开后释放ptr

//p 指向int
shared_ptr<int>p(new int(42));
process(shared_ptr<int>p);
这里p不会被释放的
p.reset(); //执行释放

这段代码本身没有问题

12.11

有两个共享指针指向了同一个区域
也就是退出函数后 p的内存已经被这个临时共享指针对象释放了

12.12

void process(shared_ptr ptr)  // 注意这里是值拷贝,也就是引用+1
{
    // 使用ptr
}
//离开后释放ptr

a 合法
b,c 非法,没有隐式转换的构造函数
d 合法,但是会删除p的内存

12.13

sp指向int
p 释放了sp的内容,但是sp的计数还在,所以sp会再次释放
也就是释放了两次

12.14

12.15

//shared_ptr<connection>p (&c,[](struct connection*p){disconnect(*p);});


/*
12.14+12.15
智能指针与异常结合的使用
当异常发生后,我们在异常发生之后的语句无法执行,比如一些资源清理操作,这个时候可以把清理动作作为一个共享指针的delte参数
shared_ptr<connection> end_link(&linkme, try_end_link);  try_end_link 在程序结束或者异常后能够执行
*/

#include <vector>
#include <memory>
#include <iostream>

using namespace std;

struct connection
{
    int fd;
};

struct disconnection
{
    int fd;
    int port;
};

connection
connect(struct disconnection *t)
{
    struct connection ret;
    ret.fd = t->port + 1;
    cout << "link to port:" << t->port << endl;
    return ret;
}

disconnection
disconnect(struct connection *t)
{
    struct disconnection ret;
    if (t->fd > 0)
    {
        ret.fd = -1;
        ret.port = t->fd - 1;
        cout << "break LINK to port:" << ret.port << endl;
        t->fd = -1;
    }

    return ret;
}

void try_end_link(struct connection *t)
{
    cout << "By shared_ptr" << endl;
    disconnect(t);
}

int main(int argc, char const *argv[])
{
    {
        struct disconnection unlinkme = {-1, 20};
        connection linkme = connect(&unlinkme);
        // disconnect(&linkme);
        //shared_ptr<connection> end_link(&linkme, try_end_link);
        shared_ptr<connection> end_link(&linkme, [](struct connection *t) {cout << "By shared_ptr" << endl;disconnect(t); });
    }
    while (1)
        ;
    return 0;
}

12.16

/*
12.16 给一个unique_ptr 赋值观察错误
*/
#include <iostream>
#include <memory>
using namespace std;

int main(int argc, char const *argv[])
{
    unique_ptr<int> p(new int(3));
    int *pint = new int(3);
    unique_ptr<int> p_unique(new int(3));

    //unique_ptr<int> s(3);

    // no known conversion for argument 1 from 'int*' to 'std::nullptr_t'
    //p = pint;

    // 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>]'
    //unique_ptr& operator=(const unique_ptr&) = delete;
    //p = p_unique;

    while (1)
        ;
    return 0;
}

12.17

下面的unique_ptr声明中,哪些是合法的,哪些可能导致后续的程序错误?
int ix = 1024, *pi = &ix, *pi2 = new int(20478);
typedef unique_ptr<int> IntP;


(a) IntP p0(ix);  非法,无法将int转为指针   
(b) IntP p1(pi);  合法,但是----原始内容是int 不是new出来的,无法del
(c) IntP p2(pi2); 合法,两个指针指向同一个内存                           
(d) IntP p3(&ix); 同b非法
(e) IntP p4(new int(2048)); 合法
(f) IntP p5(p2.get());  合法,但是----两个指针指向同一个地方

12.18

release 是放弃控制权清空unique_ptr 
release操作是用来将对象的所有权转移给另一个unique_ptr的

share_ptr 本身就没有控制权,可以相互拷贝赋值

12.19

12.20

/*
12.19 
12.20 读入文件 使用这个类

一个 StrBlob类,底层数据是指向 vector<string> 的指针
一个 StrBlob_ptr类,可以认为是StrBlob类的指针类

定义  StrBlob类,数据成员是 vector<string> 的shared_ptr
        begin  指向第一个元素的 StrBlob_ptr 也就是cur=0?
        end                   最后一个元素的指针cur=size()   end是开区间,所以不用减1
定义  StrBlob_ptr 类,指向 StrBlob类中的数据成员 *shared_ptr
        一个指向 vector<string> 的指针,带有小标
        *      获得string
        ++     将下标++


*/

#include <vector>
#include <string>
#include <memory>
#include <initializer_list>
#include <exception>
#include <iostream>
#include <fstream>

using namespace std;

class StrBlob_ptr;

class StrBlob
{
    using Blob_size_type = vector<string>::size_type;

    friend class StrBlob_ptr;

private:
    /* data */
    shared_ptr<vector<string>> data;

public:
    StrBlob() : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}

    StrBlob_ptr begin(); //{ return StrBlob_ptr(*this); }
    StrBlob_ptr end();   //{ return StrBlob_ptr(*this, data->size()); }

    Blob_size_type size() const
    {
        return data->size();
    }

    bool empty() const
    {
        return data->empty();
    }

    bool check(Blob_size_type has, const string &msg) const
    {
        if (has >= data->size())
            throw std::out_of_range(msg);
    }

    void push_back(string &s)
    {
        data->push_back(s);
    }
    void pop_back()
    {
        check(0, "pop_back");
        data->pop_back();
    }

    string &front()
    {
        check(0, "front");
        return data->front();
    }

    string &back()
    {
        check(0, "back");
        return data->back();
    }

    const string &front() const
    {
        check(0, "front");
        return data->front();
    }

    const string &back() const
    {
        check(0, "back");
        return data->back();
    }

    ~StrBlob() {}
};

class StrBlob_ptr
{
private:
    // 底层指针指向的内容是 shared_ptr,可能存在释放的情况
    weak_ptr<vector<string>> ptr;
    int cur;
    shared_ptr<vector<string>> check(int size, const string msg) const;

public:
    // 构造函数,指向空的ptr
    StrBlob_ptr() : cur(0) {}
    StrBlob_ptr(StrBlob &s, int offset = 0) : ptr(s.data), cur(offset) {}
    ~StrBlob_ptr() {}

    // * 解引用
    string &deref() const;
    StrBlob_ptr &increase_ref();
    // 同时需要定义!= 这里应该还要判断 p的指向是否相同
    bool operator!=(const StrBlob_ptr &p) { return p.cur != cur; }
};

shared_ptr<vector<string>> StrBlob_ptr::check(int size, const string msg) const
{
    auto ptr_get = ptr.lock();
    if (!ptr_get)
        throw runtime_error(msg);
    if (size >= ptr_get->size())
        throw out_of_range(msg);
    return ptr_get;
}

string &StrBlob_ptr::deref() const
{
    auto ptr_get = check(cur, "get shared_ptr");
    return (*ptr_get)[cur];
}

StrBlob_ptr &StrBlob_ptr::increase_ref()
{
    check(cur, "get shared_ptr");
    cur++;
    return *this;
}

/*
 *   这两个函数一定要放到 StrBlob_ptr 这个类下面定义,因为用到了StrBlob_ptr具体的构造函数; 即使最开始已经声明了
 *    
 *
 *
*/
StrBlob_ptr StrBlob::begin()
{
    return StrBlob_ptr(*this);
}
StrBlob_ptr StrBlob::end()
{
    return StrBlob_ptr(*this, data->size());
}

int main(int argc, const char **argv)
{

    StrBlob csb{"1", "2", "3"};
    StrBlob sb{"A1", "A2", "A3"};

    std::cout << csb.front() << " " << csb.back() << std::endl;
    sb.back() = "change";
    std::cout << sb.front() << " " << sb.back() << std::endl;

    cout << "vector string :" << endl;
    for (StrBlob_ptr ch = sb.begin(); ch != sb.end(); ch.increase_ref())
        cout << ch.deref() << ",";
    cout << endl;

    ifstream ifile("./12.19.cpp");
    StrBlob fs_blob;
    for (string str; getline(ifile, str);)
        fs_blob.push_back(str);

    cout << "file string :" << endl;
    for (StrBlob_ptr ch = fs_blob.begin(); ch != fs_blob.end(); ch.increase_ref())
        cout << ch.deref() << endl;

    while (1)
        ;
    return 0;
}

12.21

原来的好,原来的好看 哈哈哈

12.22

/*
12.19 
12.20 读入文件 使用这个类
12.22 使用  const StrBlob类
			strBlob begin end 返回const
            底层指针是个const,只有在构造的时候赋值
            解引用的时候返回const  

一个 StrBlob类,底层数据是指向 vector<string> 的指针
一个 StrBlob_ptr类,可以认为是StrBlob类的指针类

定义  StrBlob类,数据成员是 vector<string> 的shared_ptr
        begin  指向第一个元素的 StrBlob_ptr 也就是cur=0?
        end                   最后一个元素的指针cur=size()   end是开区间,所以不用减1
定义  StrBlob_ptr 类,指向 StrBlob类中的数据成员 *shared_ptr
        一个指向 vector<string> 的指针,带有小标
        *      获得string
        ++     将下标++


*/

#include <vector>
#include <string>
#include <memory>
#include <initializer_list>
#include <exception>
#include <iostream>
#include <fstream>

using namespace std;

class StrBlob_ptr;

class StrBlob
{
    using Blob_size_type = vector<string>::size_type;

    friend class StrBlob_ptr;

private:
    /* data */
    shared_ptr<vector<string>> data;

public:
    StrBlob() : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}

    StrBlob_ptr begin() const; //{ return StrBlob_ptr(*this); }
    StrBlob_ptr end() const;   //{ return StrBlob_ptr(*this, data->size()); }

    Blob_size_type size() const
    {
        return data->size();
    }

    bool empty() const
    {
        return data->empty();
    }

    bool check(Blob_size_type has, const string &msg) const
    {
        if (has >= data->size())
            throw std::out_of_range(msg);
    }

    void push_back(string &s)
    {
        data->push_back(s);
    }
    void pop_back()
    {
        check(0, "pop_back");
        data->pop_back();
    }

    string &front()
    {
        check(0, "front");
        return data->front();
    }

    string &back()
    {
        check(0, "back");
        return data->back();
    }

    const string &front() const
    {
        check(0, "front");
        return data->front();
    }

    const string &back() const
    {
        check(0, "back");
        return data->back();
    }

    ~StrBlob() {}
};

class StrBlob_ptr
{
private:
    // 底层指针指向的内容是 shared_ptr,可能存在释放的情况
    weak_ptr<vector<string>> ptr;
    int cur;
    shared_ptr<vector<string>> check(int size, const string msg) const;

public:
    // 构造函数,指向空的ptr
    StrBlob_ptr() : cur(0) {}
    StrBlob_ptr(const StrBlob &s, int offset = 0) : ptr(s.data), cur(offset) {}
    ~StrBlob_ptr() {}

    // * 解引用
    const string &deref() const;
    StrBlob_ptr &increase_ref();
    // 同时需要定义!= 这里应该还要判断 p的指向是否相同
    bool operator!=(const StrBlob_ptr &p) { return p.cur != cur; }
};

shared_ptr<vector<string>> StrBlob_ptr::check(int size, const string msg) const
{
    auto ptr_get = ptr.lock();
    if (!ptr_get)
        throw runtime_error(msg);
    if (size >= ptr_get->size())
        throw out_of_range(msg);
    return ptr_get;
}

const string &StrBlob_ptr::deref() const
{
    auto ptr_get = check(cur, "get shared_ptr");
    return (*ptr_get)[cur];
}

StrBlob_ptr &StrBlob_ptr::increase_ref()
{
    check(cur, "get shared_ptr");
    cur++;
    return *this;
}

/*
 *   这两个函数一定要放到 StrBlob_ptr 这个类下面定义,因为用到了StrBlob_ptr具体的构造函数; 即使最开始已经声明了
 *    
 *
 *
*/
StrBlob_ptr StrBlob::begin() const
{
    return StrBlob_ptr(*this);
}
StrBlob_ptr StrBlob::end() const
{
    return StrBlob_ptr(*this, data->size());
}

int main(int argc, const char **argv)
{

    const StrBlob csb{"1", "2", "3"};
    StrBlob sb{"A1", "A2", "A3"};

    std::cout << csb.front() << " " << csb.back() << std::endl;
    sb.back() = "change";
    std::cout << sb.front() << " " << sb.back() << std::endl;

    cout << "vector string :" << endl;
    for (StrBlob_ptr ch = sb.begin(); ch != sb.end(); ch.increase_ref())
        cout << ch.deref() << ",";
    cout << endl;

    ifstream ifile("./12.19.cpp");
    StrBlob fs_blob;
    for (string str; getline(ifile, str);)
        fs_blob.push_back(str);

    cout << "file string :" << endl;
    for (StrBlob_ptr ch = fs_blob.begin(); ch != fs_blob.end(); ch.increase_ref())
        cout << ch.deref() << endl;

    while (1)
        ;
    return 0;
}

12.23

/*
编写一个程序,连接两个字符串字面值常量,将结果保存在一个动态分配的char数组中。重写这个程序,连接两个标准库string对象
*/
#include <string>
#include <string.h>
#include <iostream>

using std::cout;
using std::endl;
using std::string;

int main(int argc, char const *argv[])
{

    const char *c1 = "hello";
    const char *c2 = " world";
    char *c3 = new char[strlen(c1) + strlen(c2) + 1];
    memcpy(c3, c1, strlen(c1));
    memcpy(c3 + strlen(c1), c2, strlen(c2));
    c3[strlen(c1) + strlen(c2)] = 0;

    string s1(c1), s2(c2);
    string s3 = s1 + s2;

    char *s4 = new char[s3.length()];
    strcpy(s4, s3.c_str());

    cout << string(c3) << endl;
    cout << s3 << endl;
    cout << s4 << endl;

    while (1)
        ;
    return 0;
}

12.24

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

#include <iostream>
using namespace std;

int main(int argc, char const *argv[])
{
    char c;
    char *s = new char[4];
    int i = 0;
    int len = 4;

    while (cin >> c)
    {
        if (i >= len - 1)
        {
            char *s_new = new char[len * 2];
            memcpy(s_new, s, len - 1);
            len *= 2;
            delete[] s;
            s = s_new;
            cout << "before len:" << len / 2 << ",arter len=" << len << " last char is " << s_new[i - 1] << endl;
        }
        if (c == '\r' || c == '\n')
            break;
        s[i++] = c;
    }
    s[i] = 0;
    cout << s << endl;

    while (1)
        ;
    return 0;
}

12.25

int *pa = new int[10];
如何释放pa?
    delete[] pa

12.26

/*
12.26  使用 allocater 替代new
*/
#include <iostream>
#include <string>
#include <memory>
using namespace std;

void old_test()
{
    cout << "use new[] " << endl;
    string *const p = new string[10];
    string s, *q = p;
    while (cin >> s && q != p + 10)
    {
        *q++ = s; // q=s q++
    }
    const size_t size = q - p; // 实际使用的内存
    for (int i = 0; i < size; i++)
        cout << p[i] << endl;
    delete[] p;
    cout << "end of use new[] " << endl;
}

void new_test()
{
    cout << "use allocater " << endl;
    allocator<string> allocator_string;
    auto const p = allocator_string.allocate(10);
    string *q = p;

    string s;
    while (cin >> s && q != p + 10)
    {
        allocator_string.construct(q++, s);
    }
    for (size_t i = 0; i < q - p; i++)
    {
        cout << p[i] << endl;
    }
    while (q != p)
    {
        allocator_string.destroy(--q);
    }
    allocator_string.deallocate(p, 100);
    cout << "end of use allocater " << endl;
}

int main(int argc, char const *argv[])
{
    /* code */

    //old_test();

    new_test();
    while (1)
        ;

    return 0;
}

12.27

#include <string>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <memory>

using namespace std;

// 0. 没有使用 Query类保存结果,这里的简单例子直接从 TextQuery取得结果
// 1. 使用 vector<string> 保存每行文字
// 2. 每个string 有一个set 保存行号
// 3. 使用 map<string,set>绑定这个数据

class TextQuery
{
private:
    /* data */
    vector<string> txtline;
    map<string, set<int>> data;

public:
    TextQuery(ifstream &file);
    ~TextQuery(){};
    ostream &GetWant(ostream &out, string ch);
};

TextQuery::TextQuery(ifstream &file)
{
    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline.push_back(s);
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            data[ch].insert(line_at);
        }
        line_at++;
    }
}

ostream &TextQuery::GetWant(ostream &out, string ch)
{
    out << "[" << ch << "]:" << endl;
    for (auto i = data[ch].begin(); i != data[ch].end(); i++)
        out << "Line[" << (*i) + 1 << "]: " << txtline[*i] << endl;
    return out;
}

void runQueries(ifstream &file)
{
    // 从文件流建立查询的数据
    TextQuery tq(file);
    while (true)
    {
        cout << "Enter what you want to find?" << endl;
        string s;
        if (!(cin >> s) || s == "q")
            break;
        tq.GetWant(cout, s);
    }
}

int main(int argc, char const *argv[])
{
    ifstream fs("D:\\a.txt");
    runQueries(fs);
    return 0;
}

12.27.1

#include <string>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <memory>

using namespace std;

/*
    定义一个类 保存 string,行号,以及一个指向txt的指针
*/
class ResultQuery
{
    friend ostream &print(ostream &, const ResultQuery &);

public:
    // 单词
    string w;
    // 行号的列表
    shared_ptr<set<int>> lines;
    // 全部的文本,可以通过行号寻找
    shared_ptr<vector<string>> txtline;

public:
    ResultQuery(string word, shared_ptr<set<int>> line_num, shared_ptr<vector<string>> txt) : w(word), lines(line_num), txtline(txt){};
    ~ResultQuery(){};
};

class TextQuery
{
private:
    /* data */
    shared_ptr<vector<string>> txtline;
    // 因为在ret里面共享的是set的行号,所以这里也是行号共享指针,而不是整个map
    map<string, shared_ptr<set<int>>> data;

public:
    TextQuery(ifstream &file);
    ResultQuery Query(string &w);
    ~TextQuery(){};
};

TextQuery::TextQuery(ifstream &file) : txtline(new vector<string>)
{
    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline->push_back(s);
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            if (!data[ch])
                data[ch].reset(new set<int>);
            data[ch]->insert(line_at);
        }
        line_at++;
    }
}

ResultQuery TextQuery::Query(string &w)
{
    static shared_ptr<std::set<int>> nodate(new std::set<int>);
    auto found = data.find(w);
    if (found == data.end())
        return ResultQuery(w, nodate, txtline);
    else
        return ResultQuery(w, data[w], txtline);
}
//ostream &print(ostream &, const ResultQuery &)
ostream &print(ostream &out, const ResultQuery &want)
{
    out << "----------------------------------------------" << endl;
    out << "string:" << want.w << endl;
    out << "Txt List:" << endl;
    //if (want.lines) // 先要判断指针是否存在
    {
        for (auto ls : *(want.lines))
            out << ls << ":\t\t\t" << want.txtline->at(ls) << endl;
        //qr.input->at(i)
    }

    out << "----------------------------------------------" << endl;
    return out;
}

void runQueries(ifstream &file)
{
    // 从文件流建立查询的数据
    TextQuery tq(file);
    while (true)
    {
        cout << "Enter what you want to find?" << endl;
        string s;
        if (!(cin >> s) || s == "q")
            break;
        print(cout, tq.Query(s)) << endl;
    }
}

int main(int argc, char const *argv[])
{
    ifstream fs("D:\\a.txt");
    if (fs)
        runQueries(fs);
    else
        cout << "fs open failed " << endl;

    while (1)
        ;
    return 0;
}

12.28

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

#include <string>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <memory>
using namespace std;

void test(ifstream &file)
{
    vector<string> txtline;
    map<string, set<int>> num;

    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline.push_back(s);
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            num[ch].insert(line_at);
        }
        line_at++;
    }

    string ch;
    cout << "pls input word to search" << endl;
    while (cin >> ch)
    {
        cout << "find " << ch << endl;
        for (auto i : num[ch])
        {
            cout << "line:" << i << "]:" << txtline[i] << endl;
        }
    }
}

int main(int argc, char const *argv[])
{
    ifstream fin("C:\\JLink.log");
    if (fin)
        test(fin);
    else
        cout << "check file" << endl;
    while (1)
        ;
    return 0;
}

12.29

差不多

12.31

vector 会有重复行号,需要处理相同行号

12.32

/*
12.32
重写TextQuery和QueryResult类,用StrBlob代替vector<vector>保存输入文件

TextQuery 使用StrBlob  存储shared_ptr<vector<string>>  文本
具体查询打印的时候,我们要从 *(StrBlob.ptr) 中取小标
也就是 使用 StrBlob_ptr 这个类指向了StrBlob中vector[下标]

github的答案是这里 使用 shared_ptr 执行StrBlob 也就是  shared_ptr<StrBlob> 的操作,
*/

/*
12.19 
12.20 读入文件 使用这个类
12.22 使用  const StrBlob类
			strBlob begin end 返回const
            底层指针是个const,只有在构造的时候赋值
            解引用的时候返回const  

一个 StrBlob类,底层数据是指向 vector<string> 的指针
一个 StrBlob_ptr类,可以认为是StrBlob类的指针类

定义  StrBlob类,数据成员是 vector<string> 的shared_ptr
        begin  指向第一个元素的 StrBlob_ptr 也就是cur=0?
        end                   最后一个元素的指针cur=size()   end是开区间,所以不用减1
定义  StrBlob_ptr 类,指向 StrBlob类中的数据成员 *shared_ptr
        一个指向 vector<string> 的指针,带有小标
        *      获得string
        ++     将下标++


*/

#include <vector>
#include <string>
#include <memory>
#include <initializer_list>
#include <exception>
#include <iostream>
#include <fstream>
#include <set>
#include <map>
#include <sstream>

using namespace std;

class StrBlob_ptr;

class StrBlob
{
    using Blob_size_type = vector<string>::size_type;

    friend class StrBlob_ptr;

private:
    /* data */
    shared_ptr<vector<string>> data;

public:
    StrBlob() : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}

    StrBlob_ptr begin() const; //{ return StrBlob_ptr(*this); }
    StrBlob_ptr end() const;   //{ return StrBlob_ptr(*this, data->size()); }

    Blob_size_type size() const
    {
        return data->size();
    }

    bool empty() const
    {
        return data->empty();
    }

    bool check(Blob_size_type has, const string &msg) const
    {
        if (has >= data->size())
            throw std::out_of_range(msg);
    }

    void push_back(string &s)
    {
        data->push_back(s);
    }
    void pop_back()
    {
        check(0, "pop_back");
        data->pop_back();
    }

    string &front()
    {
        check(0, "front");
        return data->front();
    }

    string &back()
    {
        check(0, "back");
        return data->back();
    }

    const string &front() const
    {
        check(0, "front");
        return data->front();
    }

    const string &back() const
    {
        check(0, "back");
        return data->back();
    }

    ~StrBlob() {}
};

class StrBlob_ptr
{
private:
    // 底层指针指向的内容是 shared_ptr,可能存在释放的情况
    weak_ptr<vector<string>> ptr;
    int cur;
    shared_ptr<vector<string>> check(int size, const string msg) const;

public:
    // 构造函数,指向空的ptr
    StrBlob_ptr() : cur(0) {}
    StrBlob_ptr(const StrBlob &s, int offset = 0) : ptr(s.data), cur(offset) {}
    ~StrBlob_ptr() {}

    // * 解引用
    const string &deref() const;
    StrBlob_ptr &increase_ref();
    // 同时需要定义!= 这里应该还要判断 p的指向是否相同
    bool operator!=(const StrBlob_ptr &p) { return p.cur != cur; }
};

shared_ptr<vector<string>> StrBlob_ptr::check(int size, const string msg) const
{
    auto ptr_get = ptr.lock();
    if (!ptr_get)
        throw runtime_error(msg);
    if (size >= ptr_get->size())
        throw out_of_range(msg);
    return ptr_get;
}

const string &StrBlob_ptr::deref() const
{
    auto ptr_get = check(cur, "get shared_ptr");
    return (*ptr_get)[cur];
}

StrBlob_ptr &StrBlob_ptr::increase_ref()
{
    check(cur, "get shared_ptr");
    cur++;
    return *this;
}

/*
 *   这两个函数一定要放到 StrBlob_ptr 这个类下面定义,因为用到了StrBlob_ptr具体的构造函数; 即使最开始已经声明了
 *    
 *
 *
*/
StrBlob_ptr StrBlob::begin() const
{
    return StrBlob_ptr(*this);
}
StrBlob_ptr StrBlob::end() const
{
    return StrBlob_ptr(*this, data->size());
}

/******************************************************************************************************************/

class ResultQuery
{
    friend ostream &print(ostream &, const ResultQuery &);

public:
    // 单词
    string w;
    // 行号的列表
    shared_ptr<set<int>> lines;
    // 全部的文本,可以通过行号寻找
    StrBlob txtline; //----------modify

public:
    ResultQuery(string word, shared_ptr<set<int>> line_num, StrBlob txt) : w(word), lines(line_num), txtline(txt){}; //----------modify
    ~ResultQuery(){};
};

class TextQuery
{
private:
    /* data */
    StrBlob txtline; //----------modify
    // 因为在ret里面共享的是set的行号,所以这里也是行号共享指针,而不是整个map
    map<string, shared_ptr<set<int>>> data;

public:
    TextQuery(ifstream &file);
    ResultQuery Query(string &w);
    ~TextQuery(){};
};

TextQuery::TextQuery(ifstream &file) : txtline() //----------modify
{
    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline.push_back(s); //----------modify
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            if (!data[ch])
                data[ch].reset(new set<int>);
            data[ch]->insert(line_at);
        }
        line_at++;
    }
}

ResultQuery TextQuery::Query(string &w)
{
    static shared_ptr<std::set<int>> nodate(new std::set<int>);
    auto found = data.find(w);
    if (found == data.end())
        return ResultQuery(w, nodate, txtline);
    else
        return ResultQuery(w, data[w], txtline);
}
//ostream &print(ostream &, const ResultQuery &)
ostream &print(ostream &out, const ResultQuery &want)
{
    out << "----------------------------------------------" << endl;
    out << "string:" << want.w << endl;
    out << "Txt List:" << endl;
    //if (want.lines) // 先要判断指针是否存在
    {
        for (auto ls : *(want.lines))
        {
            StrBlob_ptr xx(want.txtline, ls);             //----------modify
            out << ls << ":\t\t\t" << xx.deref() << endl; //----------modify
        }

        //qr.input->at(i)
    }

    out << "----------------------------------------------" << endl;
    return out;
}

void runQueries(ifstream &file)
{
    // 从文件流建立查询的数据
    TextQuery tq(file);
    while (true)
    {
        cout << "Enter what you want to find?" << endl;
        string s;
        if (!(cin >> s) || s == "q")
            break;
        print(cout, tq.Query(s)) << endl;
    }
}

int main(int argc, char const *argv[])
{
    ifstream fs("D:\\a.txt");
    if (fs)
        runQueries(fs);
    else
        cout << "fs open failed " << endl;

    while (1)
        ;
    return 0;
}

12.32.2

/*
12.32.2 
完全使用 shared_ptr<StrBlob>  替换  shared_ptr<vector<string>>


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

TextQuery 使用StrBlob  存储shared_ptr<vector<string>>  文本
具体查询打印的时候,我们要从 *(StrBlob.ptr) 中取小标
也就是 使用 StrBlob_ptr 这个类指向了StrBlob中vector[下标]

github的答案是这里 使用 shared_ptr 执行StrBlob 也就是  shared_ptr<StrBlob> 的操作,
*/

/*
12.19 
12.20 读入文件 使用这个类
12.22 使用  const StrBlob类
			strBlob begin end 返回const
            底层指针是个const,只有在构造的时候赋值
            解引用的时候返回const  

一个 StrBlob类,底层数据是指向 vector<string> 的指针
一个 StrBlob_ptr类,可以认为是StrBlob类的指针类

定义  StrBlob类,数据成员是 vector<string> 的shared_ptr
        begin  指向第一个元素的 StrBlob_ptr 也就是cur=0?
        end                   最后一个元素的指针cur=size()   end是开区间,所以不用减1
定义  StrBlob_ptr 类,指向 StrBlob类中的数据成员 *shared_ptr
        一个指向 vector<string> 的指针,带有小标
        *      获得string
        ++     将下标++


*/

#include <vector>
#include <string>
#include <memory>
#include <initializer_list>
#include <exception>
#include <iostream>
#include <fstream>
#include <set>
#include <map>
#include <sstream>

using namespace std;

class StrBlob_ptr;

class StrBlob
{
    using Blob_size_type = vector<string>::size_type;

    friend class StrBlob_ptr;

private:
    /* data */
    shared_ptr<vector<string>> data;

public:
    StrBlob() : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}

    StrBlob_ptr begin() const; //{ return StrBlob_ptr(*this); }
    StrBlob_ptr end() const;   //{ return StrBlob_ptr(*this, data->size()); }

    Blob_size_type size() const
    {
        return data->size();
    }

    bool empty() const
    {
        return data->empty();
    }

    bool check(Blob_size_type has, const string &msg) const
    {
        if (has >= data->size())
            throw std::out_of_range(msg);
    }

    void push_back(string &s)
    {
        data->push_back(s);
    }
    void pop_back()
    {
        check(0, "pop_back");
        data->pop_back();
    }

    string &front()
    {
        check(0, "front");
        return data->front();
    }

    string &back()
    {
        check(0, "back");
        return data->back();
    }

    const string &front() const
    {
        check(0, "front");
        return data->front();
    }

    const string &back() const
    {
        check(0, "back");
        return data->back();
    }

    ~StrBlob() {}
};

class StrBlob_ptr
{
private:
    // 底层指针指向的内容是 shared_ptr,可能存在释放的情况
    weak_ptr<vector<string>> ptr;
    int cur;
    shared_ptr<vector<string>> check(int size, const string msg) const;

public:
    // 构造函数,指向空的ptr
    StrBlob_ptr() : cur(0) {}
    StrBlob_ptr(const StrBlob &s, int offset = 0) : ptr(s.data), cur(offset) {}
    ~StrBlob_ptr() {}

    // * 解引用
    const string &deref() const;
    StrBlob_ptr &increase_ref();
    // 同时需要定义!= 这里应该还要判断 p的指向是否相同
    bool operator!=(const StrBlob_ptr &p) { return p.cur != cur; }
};

shared_ptr<vector<string>> StrBlob_ptr::check(int size, const string msg) const
{
    auto ptr_get = ptr.lock();
    if (!ptr_get)
        throw runtime_error(msg);
    if (size >= ptr_get->size())
        throw out_of_range(msg);
    return ptr_get;
}

const string &StrBlob_ptr::deref() const
{
    auto ptr_get = check(cur, "get shared_ptr");
    return (*ptr_get)[cur];
}

StrBlob_ptr &StrBlob_ptr::increase_ref()
{
    check(cur, "get shared_ptr");
    cur++;
    return *this;
}

/*
 *   这两个函数一定要放到 StrBlob_ptr 这个类下面定义,因为用到了StrBlob_ptr具体的构造函数; 即使最开始已经声明了
 *    
 *
 *
*/
StrBlob_ptr StrBlob::begin() const
{
    return StrBlob_ptr(*this);
}
StrBlob_ptr StrBlob::end() const
{
    return StrBlob_ptr(*this, data->size());
}

/******************************************************************************************************************/

class ResultQuery
{
    friend ostream &print(ostream &, const ResultQuery &);

public:
    // 单词
    string w;
    // 行号的列表
    shared_ptr<set<int>> lines;
    // 全部的文本,可以通过行号寻找
    shared_ptr<StrBlob> txtline; //----------modify

public:
    ResultQuery(string word, shared_ptr<set<int>> line_num, shared_ptr<StrBlob> txt) : w(word), lines(line_num), txtline(txt){}; //----------modify
    ~ResultQuery(){};
};

class TextQuery
{
private:
    /* data */
    shared_ptr<StrBlob> txtline; //----------modify
    // 因为在ret里面共享的是set的行号,所以这里也是行号共享指针,而不是整个map
    map<string, shared_ptr<set<int>>> data;

public:
    TextQuery(ifstream &file);
    ResultQuery Query(string &w);
    ~TextQuery(){};
};

TextQuery::TextQuery(ifstream &file) : txtline(new StrBlob) //----------modify
{
    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline->push_back(s); //----------modify
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            if (!data[ch])
                data[ch].reset(new set<int>);
            data[ch]->insert(line_at);
        }
        line_at++;
    }
}

ResultQuery TextQuery::Query(string &w)
{
    static shared_ptr<std::set<int>> nodate(new std::set<int>);
    auto found = data.find(w);
    if (found == data.end())
        return ResultQuery(w, nodate, txtline);
    else
        return ResultQuery(w, data[w], txtline);
}
//ostream &print(ostream &, const ResultQuery &)
ostream &print(ostream &out, const ResultQuery &want)
{
    out << "----------------------------------------------" << endl;
    out << "string:" << want.w << endl;
    out << "Txt List:" << endl;
    //if (want.lines) // 先要判断指针是否存在
    {
        for (auto ls : *(want.lines))
        {
            StrBlob_ptr xx(*(want.txtline), ls);          //----------modify
            out << ls << ":\t\t\t" << xx.deref() << endl; //----------modify
        }

        //qr.input->at(i)
    }

    out << "----------------------------------------------" << endl;
    return out;
}

void runQueries(ifstream &file)
{
    // 从文件流建立查询的数据
    TextQuery tq(file);
    while (true)
    {
        cout << "Enter what you want to find?" << endl;
        string s;
        if (!(cin >> s) || s == "q")
            break;
        print(cout, tq.Query(s)) << endl;
    }
}

int main(int argc, char const *argv[])
{
    ifstream fs("D:\\a.txt");
    if (fs)
        runQueries(fs);
    else
        cout << "fs open failed " << endl;

    while (1)
        ;
    return 0;
}

12.33

/*

12.33 增加 QueryResult 的begin,end 取得set的begin,end  增加一个get_file  返回shared_ptr 指向QueryResult的文件也就是strBlob_ptr

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

TextQuery 使用StrBlob  存储shared_ptr<vector<string>>  文本
具体查询打印的时候,我们要从 *(StrBlob.ptr) 中取小标
也就是 使用 StrBlob_ptr 这个类指向了StrBlob中vector[下标]

github的答案是这里 使用 shared_ptr 执行StrBlob 也就是  shared_ptr<StrBlob> 的操作,
*/

/*
12.19 
12.20 读入文件 使用这个类
12.22 使用  const StrBlob类
			strBlob begin end 返回const
            底层指针是个const,只有在构造的时候赋值
            解引用的时候返回const  

一个 StrBlob类,底层数据是指向 vector<string> 的指针
一个 StrBlob_ptr类,可以认为是StrBlob类的指针类

定义  StrBlob类,数据成员是 vector<string> 的shared_ptr
        begin  指向第一个元素的 StrBlob_ptr 也就是cur=0?
        end                   最后一个元素的指针cur=size()   end是开区间,所以不用减1
定义  StrBlob_ptr 类,指向 StrBlob类中的数据成员 *shared_ptr
        一个指向 vector<string> 的指针,带有小标
        *      获得string
        ++     将下标++


*/

#include <vector>
#include <string>
#include <memory>
#include <initializer_list>
#include <exception>
#include <iostream>
#include <fstream>
#include <set>
#include <map>
#include <sstream>

using namespace std;

class StrBlob_ptr;

class StrBlob
{
    using Blob_size_type = vector<string>::size_type;

    friend class StrBlob_ptr;

private:
    /* data */
    shared_ptr<vector<string>> data;

public:
    StrBlob() : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}

    StrBlob_ptr begin() const; //{ return StrBlob_ptr(*this); }
    StrBlob_ptr end() const;   //{ return StrBlob_ptr(*this, data->size()); }

    Blob_size_type size() const
    {
        return data->size();
    }

    bool empty() const
    {
        return data->empty();
    }

    bool check(Blob_size_type has, const string &msg) const
    {
        if (has >= data->size())
            throw std::out_of_range(msg);
    }

    void push_back(string &s)
    {
        data->push_back(s);
    }
    void pop_back()
    {
        check(0, "pop_back");
        data->pop_back();
    }

    string &front()
    {
        check(0, "front");
        return data->front();
    }

    string &back()
    {
        check(0, "back");
        return data->back();
    }

    const string &front() const
    {
        check(0, "front");
        return data->front();
    }

    const string &back() const
    {
        check(0, "back");
        return data->back();
    }

    ~StrBlob() {}
};

class StrBlob_ptr
{
private:
    // 底层指针指向的内容是 shared_ptr,可能存在释放的情况
    weak_ptr<vector<string>> ptr;
    int cur;
    shared_ptr<vector<string>> check(int size, const string msg) const;

public:
    // 构造函数,指向空的ptr
    StrBlob_ptr() : cur(0) {}
    StrBlob_ptr(const StrBlob &s, int offset = 0) : ptr(s.data), cur(offset) {}
    ~StrBlob_ptr() {}

    // * 解引用
    const string &deref() const;
    StrBlob_ptr &increase_ref();
    // 同时需要定义!= 这里应该还要判断 p的指向是否相同
    bool operator!=(const StrBlob_ptr &p) { return p.cur != cur; }
};

shared_ptr<vector<string>> StrBlob_ptr::check(int size, const string msg) const
{
    auto ptr_get = ptr.lock();
    if (!ptr_get)
        throw runtime_error(msg);
    if (size >= ptr_get->size())
        throw out_of_range(msg);
    return ptr_get;
}

const string &StrBlob_ptr::deref() const
{
    auto ptr_get = check(cur, "get shared_ptr");
    return (*ptr_get)[cur];
}

StrBlob_ptr &StrBlob_ptr::increase_ref()
{
    check(cur, "get shared_ptr");
    cur++;
    return *this;
}

/*
 *   这两个函数一定要放到 StrBlob_ptr 这个类下面定义,因为用到了StrBlob_ptr具体的构造函数; 即使最开始已经声明了
 *    
 *
 *
*/
StrBlob_ptr StrBlob::begin() const
{
    return StrBlob_ptr(*this);
}
StrBlob_ptr StrBlob::end() const
{
    return StrBlob_ptr(*this, data->size());
}

/******************************************************************************************************************/

class ResultQuery
{
    friend ostream &print(ostream &, const ResultQuery &);

public:
    // 单词
    string w;
    // 行号的列表
    shared_ptr<set<int>> lines;
    // 全部的文本,可以通过行号寻找
    StrBlob txtline; //----------modify

public:
    ResultQuery(string word, shared_ptr<set<int>> line_num, StrBlob txt) : w(word), lines(line_num), txtline(txt){}; //----------modify

    set<int>::iterator begin() const { return lines->begin(); } // 这里要使用const 因为下面的调用是使用  const ResultQuery&
    set<int>::iterator end() const { return lines->end(); }
    StrBlob get_file() { return txtline; }

    ~ResultQuery(){};
};

class TextQuery
{
private:
    /* data */
    StrBlob txtline; //----------modify
    // 因为在ret里面共享的是set的行号,所以这里也是行号共享指针,而不是整个map
    map<string, shared_ptr<set<int>>> data;

public:
    TextQuery(ifstream &file);
    ResultQuery Query(string &w);
    ~TextQuery(){};
};

TextQuery::TextQuery(ifstream &file) : txtline() //----------modify
{
    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline.push_back(s); //----------modify
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            if (!data[ch])
                data[ch].reset(new set<int>);
            data[ch]->insert(line_at);
        }
        line_at++;
    }
}

ResultQuery TextQuery::Query(string &w)
{
    static shared_ptr<std::set<int>> nodate(new std::set<int>);
    auto found = data.find(w);
    if (found == data.end())
        return ResultQuery(w, nodate, txtline);
    else
        return ResultQuery(w, data[w], txtline);
}
//ostream &print(ostream &, const ResultQuery &)
ostream &print(ostream &out, const ResultQuery &want)
{
    out << "----------------------------------------------" << endl;
    out << "string:" << want.w << endl;
    out << "Txt List:" << endl;

    for (auto it = want.begin(); it != want.end(); it++)
    {
        StrBlob_ptr xx(want.txtline, *it);             //----------modify
        out << *it << ":\t\t\t" << xx.deref() << endl; //----------modify
    }

    //for(auto it=want.begin();)
    //if (want.lines) // 先要判断指针是否存在
    {
        // for (auto ls : *(want.lines))
        // {
        //     StrBlob_ptr xx(want.txtline, ls);             //----------modify
        //     out << ls << ":\t\t\t" << xx.deref() << endl; //----------modify
        // }

        //qr.input->at(i)
    }

    out << "----------------------------------------------" << endl;
    return out;
}

void runQueries(ifstream &file)
{
    // 从文件流建立查询的数据
    TextQuery tq(file);
    while (true)
    {
        cout << "Enter what you want to find?" << endl;
        string s;
        if (!(cin >> s) || s == "q")
            break;
        print(cout, tq.Query(s)) << endl;
    }
}

int main(int argc, char const *argv[])
{
    ifstream fs("D:\\a.txt");
    if (fs)
        runQueries(fs);
    else
        cout << "fs open failed " << endl;

    while (1)
        ;
    return 0;
}

12.33.2

/*

12.33.2 
完全使用 shared_ptr<StrBlob>  替换  shared_ptr<vector<string>>

12.33 增加 QueryResult 的begin,end 取得set的begin,end  增加一个get_file  返回shared_ptr 指向QueryResult的文件也就是strBlob_ptr

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

TextQuery 使用StrBlob  存储shared_ptr<vector<string>>  文本
具体查询打印的时候,我们要从 *(StrBlob.ptr) 中取小标
也就是 使用 StrBlob_ptr 这个类指向了StrBlob中vector[下标]

github的答案是这里 使用 shared_ptr 执行StrBlob 也就是  shared_ptr<StrBlob> 的操作,
*/

/*
12.19 
12.20 读入文件 使用这个类
12.22 使用  const StrBlob类
			strBlob begin end 返回const
            底层指针是个const,只有在构造的时候赋值
            解引用的时候返回const  

一个 StrBlob类,底层数据是指向 vector<string> 的指针
一个 StrBlob_ptr类,可以认为是StrBlob类的指针类

定义  StrBlob类,数据成员是 vector<string> 的shared_ptr
        begin  指向第一个元素的 StrBlob_ptr 也就是cur=0?
        end                   最后一个元素的指针cur=size()   end是开区间,所以不用减1
定义  StrBlob_ptr 类,指向 StrBlob类中的数据成员 *shared_ptr
        一个指向 vector<string> 的指针,带有小标
        *      获得string
        ++     将下标++


*/

#include <vector>
#include <string>
#include <memory>
#include <initializer_list>
#include <exception>
#include <iostream>
#include <fstream>
#include <set>
#include <map>
#include <sstream>

using namespace std;

class StrBlob_ptr;

class StrBlob
{
    using Blob_size_type = vector<string>::size_type;

    friend class StrBlob_ptr;

private:
    /* data */
    shared_ptr<vector<string>> data;

public:
    StrBlob() : data(make_shared<vector<string>>()) {}
    StrBlob(initializer_list<string> li) : data(make_shared<vector<string>>(li)) {}

    StrBlob_ptr begin() const; //{ return StrBlob_ptr(*this); }
    StrBlob_ptr end() const;   //{ return StrBlob_ptr(*this, data->size()); }

    Blob_size_type size() const
    {
        return data->size();
    }

    bool empty() const
    {
        return data->empty();
    }

    bool check(Blob_size_type has, const string &msg) const
    {
        if (has >= data->size())
            throw std::out_of_range(msg);
    }

    void push_back(string &s)
    {
        data->push_back(s);
    }
    void pop_back()
    {
        check(0, "pop_back");
        data->pop_back();
    }

    string &front()
    {
        check(0, "front");
        return data->front();
    }

    string &back()
    {
        check(0, "back");
        return data->back();
    }

    const string &front() const
    {
        check(0, "front");
        return data->front();
    }

    const string &back() const
    {
        check(0, "back");
        return data->back();
    }

    ~StrBlob() {}
};

class StrBlob_ptr
{
private:
    // 底层指针指向的内容是 shared_ptr,可能存在释放的情况
    weak_ptr<vector<string>> ptr;
    int cur;
    shared_ptr<vector<string>> check(int size, const string msg) const;

public:
    // 构造函数,指向空的ptr
    StrBlob_ptr() : cur(0) {}
    StrBlob_ptr(const StrBlob &s, int offset = 0) : ptr(s.data), cur(offset) {}
    ~StrBlob_ptr() {}

    // * 解引用
    const string &deref() const;
    StrBlob_ptr &increase_ref();
    // 同时需要定义!= 这里应该还要判断 p的指向是否相同
    bool operator!=(const StrBlob_ptr &p) { return p.cur != cur; }
};

shared_ptr<vector<string>> StrBlob_ptr::check(int size, const string msg) const
{
    auto ptr_get = ptr.lock();
    if (!ptr_get)
        throw runtime_error(msg);
    if (size >= ptr_get->size())
        throw out_of_range(msg);
    return ptr_get;
}

const string &StrBlob_ptr::deref() const
{
    auto ptr_get = check(cur, "get shared_ptr");
    return (*ptr_get)[cur];
}

StrBlob_ptr &StrBlob_ptr::increase_ref()
{
    check(cur, "get shared_ptr");
    cur++;
    return *this;
}

/*
 *   这两个函数一定要放到 StrBlob_ptr 这个类下面定义,因为用到了StrBlob_ptr具体的构造函数; 即使最开始已经声明了
 *    
 *
 *
*/
StrBlob_ptr StrBlob::begin() const
{
    return StrBlob_ptr(*this);
}
StrBlob_ptr StrBlob::end() const
{
    return StrBlob_ptr(*this, data->size());
}

/******************************************************************************************************************/

class ResultQuery
{
    friend ostream &print(ostream &, const ResultQuery &);

public:
    // 单词
    string w;
    // 行号的列表
    shared_ptr<set<int>> lines;
    // 全部的文本,可以通过行号寻找
    shared_ptr<StrBlob> txtline; //----------modify

public:
    ResultQuery(string word, shared_ptr<set<int>> line_num, shared_ptr<StrBlob> txt) : w(word), lines(line_num), txtline(txt){}; //----------modify

    set<int>::iterator begin() const { return lines->begin(); } // 这里要使用const 因为下面的调用是使用  const ResultQuery&
    set<int>::iterator end() const { return lines->end(); }
    shared_ptr<StrBlob> get_file() const { return txtline; } //modify

    ~ResultQuery(){};
};

class TextQuery
{
private:
    /* data */
    shared_ptr<StrBlob> txtline; //----------modify
    // 因为在ret里面共享的是set的行号,所以这里也是行号共享指针,而不是整个map
    map<string, shared_ptr<set<int>>> data;

public:
    TextQuery(ifstream &file);
    ResultQuery Query(string &w);
    ~TextQuery(){};
};

TextQuery::TextQuery(ifstream &file) : txtline(new StrBlob) //----------modify
{
    // 读入文件到文件流,保存每一行到vector<string>
    string s;
    int line_at = 0;
    while (getline(file, s))
    {
        txtline->push_back(s); //----------modify
        string ch;
        istringstream ss(s);
        while (ss >> ch)
        {
            if (!data[ch])
                data[ch].reset(new set<int>);
            data[ch]->insert(line_at);
        }
        line_at++;
    }
}

ResultQuery TextQuery::Query(string &w)
{
    static shared_ptr<std::set<int>> nodate(new std::set<int>);
    auto found = data.find(w);
    if (found == data.end())
        return ResultQuery(w, nodate, txtline);
    else
        return ResultQuery(w, data[w], txtline);
}
//ostream &print(ostream &, const ResultQuery &)
ostream &print(ostream &out, const ResultQuery &want)
{
    out << "----------------------------------------------" << endl;
    out << "string:" << want.w << endl;
    out << "Txt List:" << endl;

    for (auto it = want.begin(); it != want.end(); it++)
    {
        StrBlob_ptr xx(*(want.get_file()), *it);
        //StrBlob_ptr xx(*(want.txtline), *it);          //----------modify
        out << *it << ":\t\t\t" << xx.deref() << endl; //----------modify
    }

    //for(auto it=want.begin();)
    //if (want.lines) // 先要判断指针是否存在
    {
        // for (auto ls : *(want.lines))
        // {
        //     StrBlob_ptr xx(want.txtline, ls);             //----------modify
        //     out << ls << ":\t\t\t" << xx.deref() << endl; //----------modify
        // }

        //qr.input->at(i)
    }

    out << "----------------------------------------------" << endl;
    return out;
}

void runQueries(ifstream &file)
{
    // 从文件流建立查询的数据
    TextQuery tq(file);
    while (true)
    {
        cout << "Enter what you want to find?" << endl;
        string s;
        if (!(cin >> s) || s == "q")
            break;
        print(cout, tq.Query(s)) << endl;
    }
}

int main(int argc, char const *argv[])
{
    ifstream fs("D:\\a.txt");
    if (fs)
        runQueries(fs);
    else
        cout << "fs open failed " << endl;

    while (1)
        ;
    return 0;
}

posted @ 2020-03-14 10:18  zongzi10010  阅读(281)  评论(0编辑  收藏  举报