zoukankan      html  css  js  c++  java
  • 第十二章 动态内存

    12.1

    b1和b2各包含4个元素,且这4个元素是b1和b2共享的。

    更多:StrBlob的data成员是一个指向string的vector(即vector<string>)的shared_ptr,因此StrBlob的赋值不会拷贝vector的内容,而是多个StrBlob对象共享同一个vector对象。因此题目中尽管只是对b2进行了增加元素的操作,但结果就是b1和b2均包含4个string。

    12.2

     1 #ifndef MY_STRBLOB_H
     2 #define MY_STRBLOB_H
     3 #include <iostream>
     4 #include <memory>
     5 #include <string>
     6 #include <initializer_list>
     7 #include <vector>
     8 #include <stdexcept>
     9 
    10 //using声明在头文件中的全局作用域中
    11 //在相应的实现文件就不要再次声明了 
    12 using std::shared_ptr;
    13 using std::make_shared;
    14 using std::vector;
    15 using std::string;
    16 using std::initializer_list;
    17 using std::out_of_range;
    18 using std::cin;
    19 using std::cout;
    20 using std::endl;
    21 
    22 class StrBlob {
    23 public:
    24     using size_type = vector<string>::size_type;
    25     StrBlob();
    26     StrBlob(initializer_list<string> il);
    27     size_type size() const { return data->size(); }
    28     bool empty() const { return data->empty(); }
    29     void push_back(const string &s);
    30     void pop_back();
    31     //返回string的引用,是因为调用点会使用该string
    32     //如b.front() = "first"; 
    33     string& front();
    34     string& back();
    35     //只有const StrBlob对象才会调用以下函数 
    36     const string& front() const;
    37     const string& back() const;
    38 private:
    39     shared_ptr<vector<string>> data;
    40     void check(size_type i, const string &msg) const; 
    41 }; 
    42 
    43 StrBlob::StrBlob(): data(make_shared<vector<string>>())
    44 {
    45 }
    46 
    47 StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il))
    48 {    
    49 }
    50 
    51 void StrBlob::check(size_type i, const string &msg) const
    52 {
    53     if (i >= data->size())
    54         throw out_of_range(msg);
    55 }
    56 
    57 void StrBlob::push_back(const string &s)
    58 {
    59     data->push_back(s);
    60 }
    61 
    62 void StrBlob::pop_back()
    63 {
    64     check(0, "此StrBlob对象指向一个空vector!
    ");
    65     data->pop_back();
    66 }
    67 
    68 string& StrBlob::front()
    69 {
    70     check(0, "此StrBlob对象指向一个空vector!
    ");
    71     return data->front();
    72 }
    73 
    74 string& StrBlob::back()
    75 {
    76     check(0, "此StrBlob对象指向一个空vector!
    ");
    77     return data->back();
    78 }
    79 
    80 const string& StrBlob::front() const
    81 {
    82     check(0, "此StrBlob对象指向一个空vector!
    ");
    83     cout << "调用对象为const StrBlob!
    ";
    84     return data->front();
    85 }
    86 
    87 const string& StrBlob::back() const
    88 {
    89     check(0, "此StrBlob对象指向一个空vector!
    ");
    90     cout << "调用对象为const StrBlob!
    ";
    91     return data->back();
    92 }
    93 #endif
    StrBlob.h
     1 #include <iostream>
     2 #include "StrBlob.h"
     3 
     4     StrBlob b1;
     5 
     6 void func()
     7 {
     8     StrBlob b2{"first", "second", "third"};
     9     b1 = b2;        //b1和b2指向同一vector<string>对象,该对象引用计数为2 
    10     cout << b1.size() << endl;
    11     b2.front() = "zero";
    12     cout << b1.front() << endl; 
    13 }
    14 
    15 int main()
    16 {
    17     func();
    18     //b1指向的对象引用计数递减,现为1 
    19     cout << b1.size() << endl; 
    20     return 0;
    21 }
    StrBlobCpp.cpp

    12.3

    不需要。push_back和pop_back的功能分别是向StrBlob对象共享的vector对象添加和删除元素。因此,我们不应该为其重载const版本,因为const版本只能被const对象调用,而常量StrBlob对象是不应该被允许修改共享vector对象的内容的。

    12.4

    size_type是无符号类型,即使 i 是负数,也会自动转换为非负数。

    12.5

    观点一:

    explicit的作用就是抑制构造函数的隐式转换

    优点:不会自动的进行类型转换,必须清楚的知道类类型

    缺点:必须用构造函数显示创建一个对象,不够方便简单

    观点二:

    使用容易,因为可以自动转换参数类型

    调试难,出问题时就悲剧

    观点三:

    未编写一个初始化列表参数的显式构造函数,意味着可以进行列表向StrBlob的隐式类型转换,在需要StrBlob的地方可以使用列表进行替代。而且还可以进行拷贝形式的初始化,这令程序编写更为简单方便。

    但这种隐式转换并不总是好的。例如,列表中可能并非都是合法的值。再如,对于接受StrBlob的函数,传递给它一个列表,会创建一个临时的StrBlob对象,用列表对其初始化,然后将其传递给函数,当函数完成后,此对象将被丢弃,再也无法访问了。

    12.6

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <iterator>
     5 #include <initializer_list>
     6 #include <vector> 
     7 #include <string>
     8 #include <deque>
     9 #include <list> 
    10 #include <forward_list>
    11 #include <array>
    12 #include <stack>
    13 #include <queue>
    14 #include <algorithm> 
    15 #include <functional>
    16 #include <map>
    17 #include <set> 
    18 #include <cctype>
    19 #include <unordered_map>
    20 #include <unordered_set>
    21 #include <memory> 
    22 #include <new> 
    23  
    24 using namespace std;
    25 using namespace std::placeholders;
    26 
    27 vector<int> *func()
    28 {
    29     return new vector<int>();
    30 } 
    31 
    32 void func2()
    33 {
    34     int i;
    35     vector<int> *pv = func();
    36     while (cin >> i) {
    37         (*pv).push_back(i);
    38     }
    39     for (auto &v : *pv)
    40         cout << v << " ";
    41     cout << endl;
    42     delete pv;
    43     pv = nullptr;
    44 }
    45 
    46 
    47 int main()
    48 {
    49     func2();
    50     return 0;
    51 }
    View Code

    12.7

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <iterator>
     5 #include <initializer_list>
     6 #include <vector> 
     7 #include <string>
     8 #include <deque>
     9 #include <list> 
    10 #include <forward_list>
    11 #include <array>
    12 #include <stack>
    13 #include <queue>
    14 #include <algorithm> 
    15 #include <functional>
    16 #include <map>
    17 #include <set> 
    18 #include <cctype>
    19 #include <unordered_map>
    20 #include <unordered_set>
    21 #include <memory> 
    22 #include <new> 
    23  
    24 using namespace std;
    25 using namespace std::placeholders;
    26 
    27 shared_ptr<vector<int>> func()                //修改处1 
    28 {
    29     return make_shared<vector<int>>();        //修改处2 
    30 } 
    31 
    32 void func2()
    33 {
    34     int i;
    35     auto spv = func();    //即shared_ptr<vector<int>> spv = func(); 
    36     while (cin >> i) {
    37         (*spv).push_back(i);
    38     }
    39     for (auto &v : *spv)
    40         cout << v << " ";
    41     cout << endl;
    42 }
    43 
    44 
    45 int main()
    46 {
    47     func2();
    48     return 0;
    49 }
    View Code

    12.8

    错误:这段程序的意图是判断分配动态内存是否成功(p的值可以转换为整型值,再转换为bool值),若自由空间被耗尽,则new不能分配所要求的内存空间,它就会抛出一个类型为bad_alloc的异常,而不是返回nullptr,即不会返回false,故程序在自由空间被耗尽时将达不到预期的目的。可将new int改为new (nothrow) int 来令new在分配失败时不抛出异常,而是返回nullptr。但这仍然不是一个好方法,应该通过捕获异常或是判断返回的指针来判断true或false,而不是依赖类型转换。除此,本段程序并没有释放分配的动态内存,会造成内存泄漏。

    12.9

    r = q:r原先指向的内存没有释放,变为孤儿内存,会造成内存泄漏

    r2 = q2:递增q2指向的对象的引用计数,递减r2原来指向的对象的引用计数(r2原来指向的对象已没有引用者,会自动释放)

    补充:1.首先是一个直接的内存泄露的问题,r和q一样都指向42的内存地址,而r中原来保存的地址——100的内存再无指针管理,变成“孤儿内存”,从而造成内存泄漏。 2.其次是一个“空悬指针“的问题。由于r和q指向同一个动态对象,如果程序编写不当,很容易产生释放了其中一个指针,而继续使用另一个指针的问题。继续使用的指针指向的是一块已经释放的内存,是一个空悬指针,继续读写它指向的内存可能导致程序崩溃甚至系统崩溃的严重问题。 而shared_ptr则可很好地解决这些问题。首先,分配了两个共享的对象,分别由共享指针p2和g2指向,因而它们的引用计数均为1.接下来,将q2赋予r2,。赋值操作会将q2指向的对象地址赋予r2,并将r2原来指向的对象的引用计数减1,将q2指向的对象的引用计数加1。这样,前者的引用计数变为0,其占用的内存空间会被释放,不会造成内存泄露。而后者的引用计数变为2,也不会因为r2和q2之一的销毁而释放它的内存空间,因此也不会造成空悬指针的问题。

    12.10

    正确:我们将一个利用p创建的临时shared_ptr传递给process,此时p和临时对象都指向相同的int对象,引用计数被正确地置为2。当这个调用表达式结束后,这个临时对象就被销毁了,引用计数递减,只有p指向该对象。

    12.11

    知识点:p.get()返回一个内置指针,指向智能指针p管理的对象,但是使用该内置指针的代码不能delete此指针。

    该调用语句用get返回的指针创建了一个临时对象,这与用p创建临时对象不同,因为使用get返回的指针创建的临时对象与p是两个独立的shared_ptr(尽管它们指向相同的内存),所以该临时对象的引用计数为1,当调用语句结束后,这个临时对象被销毁,同时引用计数减1,变为0,故该临时对象指向的内存也被释放,而p也指向该内存,故p将变为一个空悬指针。

    12.12

    (a):合法,将智能指针sp传给函数process()

    补充:process()被调用时智能指针ptr被创建并由sp初始化,故sp的引用计数加1,调用结束后,sp的引用计数减1

    (b):不合法,new分配内存后返回的是一个普通指针,无法赋值到shared_ptr对象

    (c):不合法,p是一个普通指针,不能赋值到shared_ptr对象

    (d):合法,由p创建一个临时对象传给函数process

    补充:因为不是由p.get()返回的指针创建的,故不会造成内存泄漏

    12.13

    sp指向的内存被释放(sp的引用计数仍为1),sp变为空悬指针。

    12.14

    #include <iostream>
    #include <memory>
    
    using namespace std;
    
    struct destination;
    void f(destination *d);
    
    struct destination {
    	string addr = "192.168.87.130";
    };
    
    struct connection {
    	bool isConnect = false;
    };
    
    connection connect(destination *dest)
    {
    	cout << "succeed to connect to : " << dest->addr << endl;
    	connection conn;
    	conn.isConnect = true;
    	return conn;
    }
    
    void disconnect(connection *conn)
    {
    	cout << "close connection...
    ";
    	conn->isConnect = false;
    }
    
    void end_connection(connection *p)
    {
    	disconnect(p);
    }
    
    int main()
    {
    	destination destin;
    	f(&destin);
    	return 0;
    }
    
    void f(destination *d)
    {
    	connection c = connect(d);
    	shared_ptr<connection> pc(&c, end_connection);
    //	throw exception();
    }

    12.15

    void f(destination *d)
    {
    	connection c = connect(d);
    	auto func = [](connection *p)->void { disconnect(p); };
    	shared_ptr<connection> pc(&c, func);    	// 下同 
    //	shared_ptr<connection> pc(&c, [](connection *p)->void{ disconnect(p); } );
    //	throw exception();
    }

    12.17

    知识点:定义一个unique_str时,需要将其绑定到一个new返回的指针上,而且必须采用直接初始化形式

    知识点:任一时刻只能有一个unique_ptr指向一个给定对象

    (a):错误,ix不是new返回的指针

    (b):错误,同上

    (c):合法

    (d):错误,同上

    (e):合法

    (f ):错误,p2.get()返回的确实可能是是一个指向动态内存的普通指针,但是unqiue_str指向的内存空间只能有它

    12.18

    release()的功能是:放弃对指针的控制权(即该智能指针不再指向该内存空间),而让别的uniqe_str指针可以指向该内存空间,这是由于unqie_str与内存空间一对一的关系所致,而shared_str并不需要这么麻烦地转接内存空间的所有权,故没必要设置这一函数。

    12.19

      1 #include <iostream>
      2 #include <memory>
      3 #include <string>
      4 #include <initializer_list>
      5 #include <vector>
      6 #include <stdexcept>
      7 
      8 using namespace std;
      9 
     10 class StrBlobPtr;
     11 
     12 class StrBlob {
     13     friend class StrBlobPtr;
     14 public:
     15     using size_type = vector<string>::size_type;
     16     StrBlob();
     17     StrBlob(initializer_list<string> il);
     18     size_type size() const { return data->size(); }
     19     bool empty() const { return data->empty(); }
     20     void push_back(const string &s);
     21     void pop_back();
     22     //返回string的引用,是因为调用点会使用该string
     23     //如b.front() = "first"; 
     24     string& front();
     25     string& back();
     26     //只有const StrBlob对象才会调用以下函数 
     27     const string& front() const;
     28     const string& back() const;
     29     StrBlobPtr begin();
     30     StrBlobPtr end();
     31 private:
     32     shared_ptr<vector<string>> data;
     33     void check(size_type i, const string &msg) const; 
     34 }; 
     35 
     36 StrBlob::StrBlob(): data(make_shared<vector<string>>())
     37 {
     38 }
     39 
     40 StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il))
     41 {    
     42 }
     43 
     44 void StrBlob::check(size_type i, const string &msg) const
     45 {
     46     if (i >= data->size())
     47         throw out_of_range(msg);
     48 }
     49 
     50 void StrBlob::push_back(const string &s)
     51 {
     52     data->push_back(s);
     53 }
     54 
     55 void StrBlob::pop_back()
     56 {
     57     check(0, "此StrBlob对象指向一个空vector!
    ");
     58     data->pop_back();
     59 }
     60 
     61 string& StrBlob::front()
     62 {
     63     check(0, "此StrBlob对象指向一个空vector!
    ");
     64     return data->front();
     65 }
     66 
     67 string& StrBlob::back()
     68 {
     69     check(0, "此StrBlob对象指向一个空vector!
    ");
     70     return data->back();
     71 }
     72 
     73 const string& StrBlob::front() const
     74 {
     75     check(0, "此StrBlob对象指向一个空vector!
    ");
     76     cout << "调用对象为const StrBlob!
    ";
     77     return data->front();
     78 }
     79 
     80 const string& StrBlob::back() const
     81 {
     82     check(0, "此StrBlob对象指向一个空vector!
    ");
     83     cout << "调用对象为const StrBlob!
    ";
     84     return data->back();
     85 }
     86 
     87 class StrBlobPtr {
     88 public:
     89     StrBlobPtr(): curr(0) {}
     90     StrBlobPtr(StrBlob &b, size_t sz = 0): wptr(b.data), curr(sz) {}
     91     string& deref() const;
     92     StrBlobPtr& incr(); 
     93 private:
     94     weak_ptr<vector<string>> wptr;
     95     size_t curr;
     96     shared_ptr<vector<string>> check(size_t i, const string &msg) const;
     97 };
     98 
     99 shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const
    100 {
    101     auto ret = wptr.lock();
    102     if (!ret)
    103         throw runtime_error("要访问的vector<string>对象不存在!
    ");
    104     if (i >= ret->size())
    105         throw out_of_range(msg);
    106     return ret;
    107 }
    108 
    109 string& StrBlobPtr::deref() const
    110 {
    111     auto p = check(curr, "当前下标不合法!
    ");
    112     return (*p)[curr]; 
    113 }
    114 
    115 StrBlobPtr& StrBlobPtr::incr()
    116 {
    117     check(curr, "不能继续递增了
    ");
    118     ++curr;
    119     return *this;
    120 }
    121 
    122 StrBlobPtr StrBlob::begin() 
    123 {
    124     return StrBlobPtr(*this); 
    125 }
    126 
    127 StrBlobPtr StrBlob::end() 
    128 { 
    129     return StrBlobPtr(*this, data->size()); 
    130 }
    131 
    132 int main()
    133 {
    134     StrBlob b1{"mon", "tue", "wed", "thu", "fri"};
    135     StrBlobPtr p(b1, 3);
    136     cout << p.deref() << endl;            //访问p当前指向的元素 
    137     cout << p.incr().deref() << endl;    //先递增p,再访问元素 
    138     p = b1.begin();
    139     cout << p.deref() << endl;
    140     return 0; 
    141 }
    View Code 

    12.20

      1 #include <iostream>
      2 #include <fstream>
      3 #include <memory>
      4 #include <string>
      5 #include <initializer_list>
      6 #include <vector>
      7 #include <stdexcept>
      8 
      9 using namespace std;
     10 
     11 class StrBlobPtr;
     12 
     13 class StrBlob {
     14     friend class StrBlobPtr;
     15 public:
     16     using size_type = vector<string>::size_type;
     17     StrBlob();
     18     StrBlob(initializer_list<string> il);
     19     size_type size() const { return data->size(); }
     20     bool empty() const { return data->empty(); }
     21     void push_back(const string &s);
     22     void pop_back();
     23     //返回string的引用,是因为调用点会使用该string
     24     //如b.front() = "first"; 
     25     string& front();
     26     string& back();
     27     //只有const StrBlob对象才会调用以下函数 
     28     const string& front() const;
     29     const string& back() const;
     30     StrBlobPtr begin();
     31     StrBlobPtr end();
     32 private:
     33     shared_ptr<vector<string>> data;
     34     void check(size_type i, const string &msg) const; 
     35 }; 
     36 
     37 StrBlob::StrBlob(): data(make_shared<vector<string>>())
     38 {
     39 }
     40 
     41 StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il))
     42 {    
     43 }
     44 
     45 void StrBlob::check(size_type i, const string &msg) const
     46 {
     47     if (i >= data->size())
     48         throw out_of_range(msg);
     49 }
     50 
     51 void StrBlob::push_back(const string &s)
     52 {
     53     data->push_back(s);
     54 }
     55 
     56 void StrBlob::pop_back()
     57 {
     58     check(0, "此StrBlob对象指向一个空vector!
    ");
     59     data->pop_back();
     60 }
     61 
     62 string& StrBlob::front()
     63 {
     64     check(0, "此StrBlob对象指向一个空vector!
    ");
     65     return data->front();
     66 }
     67 
     68 string& StrBlob::back()
     69 {
     70     check(0, "此StrBlob对象指向一个空vector!
    ");
     71     return data->back();
     72 }
     73 
     74 const string& StrBlob::front() const
     75 {
     76     check(0, "此StrBlob对象指向一个空vector!
    ");
     77     cout << "调用对象为const StrBlob!
    ";
     78     return data->front();
     79 }
     80 
     81 const string& StrBlob::back() const
     82 {
     83     check(0, "此StrBlob对象指向一个空vector!
    ");
     84     cout << "调用对象为const StrBlob!
    ";
     85     return data->back();
     86 }
     87 
     88 class StrBlobPtr {
     89 public:
     90     StrBlobPtr(): curr(0) {}
     91     StrBlobPtr(StrBlob &b, size_t sz = 0): wptr(b.data), curr(sz) {}
     92     string& deref() const;
     93     StrBlobPtr& incr(); 
     94     bool operator!=(const StrBlobPtr &rhs) const;
     95 private:
     96     weak_ptr<vector<string>> wptr;
     97     size_t curr;
     98     shared_ptr<vector<string>> check(size_t i, const string &msg) const;
     99 };
    100 
    101 shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const
    102 {
    103     auto ret = wptr.lock();
    104     if (!ret)
    105         throw runtime_error("要访问的vector<string>对象不存在!
    ");
    106     if (i >= ret->size())
    107         throw out_of_range(msg);
    108     return ret;
    109 }
    110 
    111 string& StrBlobPtr::deref() const
    112 {
    113     auto p = check(curr, "当前下标不合法!
    ");
    114     return (*p)[curr]; 
    115 }
    116 
    117 StrBlobPtr& StrBlobPtr::incr()
    118 {
    119     check(curr, "不能继续递增了
    ");
    120     ++curr;
    121     return *this;
    122 }
    123 
    124 //判断两个StrBlobPtr对象是否相等
    125 bool StrBlobPtr::operator!=(const StrBlobPtr &rhs) const
    126 {
    127     return wptr.lock() != rhs.wptr.lock() || curr != rhs.curr;
    128 }
    129 
    130 StrBlobPtr StrBlob::begin() 
    131 {
    132     return StrBlobPtr(*this); 
    133 }
    134 
    135 StrBlobPtr StrBlob::end() 
    136 { 
    137     return StrBlobPtr(*this, data->size()); 
    138 }
    139 
    140 int main()
    141 {
    142     ifstream in("data.txt");
    143     string line;
    144     StrBlob b;
    145     while (getline(in, line)) {
    146         b.push_back(line);
    147     }
    148     StrBlobPtr pb(b);
    149     while (pb != b.end()) {
    150         cout << pb.deref() << endl;
    151         pb.incr();
    152     }
    153     return 0; 
    154 }
    View Code

    12.21

    前一个版本更好,因为它将合法性检查与元素获取的返回语句分离开来,代码更清晰易读,当执行到第二条语句时,已确保p是存在的vector,curr是合法的位置,可安全地获取元素并返回。这种清晰的结构也更有利于修改不同的处理逻辑。 而本题中的版本将合法性检查和元素获取及返回合在一条语句中,不易读,也不易修改。

    12.22

    class ConstStrBlobPtr{
    	friend bool eq(const ConstStrBlobPtr &, const ConstStrBlobPtr &);  
    public:
    	ConstStrBlobPtr(): curr(0) {}
    	ConstStrBlobPtr(const StrBlob &a, size_t sz = 0): wptr(a.data), curr(sz) {}
    	string &deref() const;		//解引用 
    	ConstStrBlobPtr &incr();			//递增StrBlobPtr 
    private:
    	weak_ptr<vector<string>> wptr;
    	size_t curr;
    	shared_ptr<vector<string>> check(size_t, const string &) const;
    }; 
    

    12.23

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <iterator>
     5 #include <initializer_list>
     6 #include <vector> 
     7 #include <string>
     8 #include <cstring>
     9 #include <deque>
    10 #include <list> 
    11 #include <forward_list>
    12 #include <array>
    13 #include <stack>
    14 #include <queue>
    15 #include <algorithm> 
    16 #include <functional>
    17 #include <map>
    18 #include <set> 
    19 #include <cctype>
    20 #include <unordered_map>
    21 #include <unordered_set>
    22 #include <memory> 
    23 #include <new> 
    24  
    25 using namespace std;
    26 using namespace std::placeholders;
    27 
    28 void func1()
    29 {
    30     char str1[] = "hello", str2[] = " world!";
    31     int len = strlen(str1) + strlen(str2);
    32     char *p = new char[len + 1];
    33     strcpy(p, str1);
    34     strcat(p, str2);
    35 //    for (int i = 0; i != len + 1; ++i) 
    36 //        cout << *(p+i);
    37     cout << p << endl;
    38 }
    39 
    40 void func2()
    41 {
    42     string s1 = "hello", s2 = " world!";
    43     int len = s1.size() + s2.size();
    44     char *p = new char[len + 1];
    45     strcpy(p, (s1+s2).c_str());    //必须转换为c类型字符串(c中无string类型)  
    46     cout << p << endl;
    47 }
    48 
    49 int main()
    50 {
    51     func1();
    52     func2();
    53     return 0;
    54 }
    View Code

    忘记释放内存,引以为戒!!! 

    12.24

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <iterator>
     5 #include <initializer_list>
     6 #include <vector> 
     7 #include <string>
     8 #include <cstring>
     9 #include <deque>
    10 #include <list> 
    11 #include <forward_list>
    12 #include <array>
    13 #include <stack>
    14 #include <queue>
    15 #include <algorithm> 
    16 #include <functional>
    17 #include <map>
    18 #include <set> 
    19 #include <cctype>
    20 #include <unordered_map>
    21 #include <unordered_set>
    22 #include <memory> 
    23 #include <new> 
    24  
    25 using namespace std;
    26 using namespace std::placeholders;
    27 
    28 void func()
    29 {
    30     char *p = new char[10];
    31     cin.get(p, 10);    //只读取10个字符
    32     cout << p << endl; 
    33     delete []p;
    34 }
    35 
    36 int main()
    37 {
    38     func();
    39     return 0;
    40 }
    View Code

    我的程序只读取与分配长度相等长度的字符串,多出部分会自动忽略。

    12.25

    delete []pa;

    12.26

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <iterator>
     5 #include <initializer_list>
     6 #include <vector> 
     7 #include <string>
     8 #include <cstring>
     9 #include <deque>
    10 #include <list> 
    11 #include <forward_list>
    12 #include <array>
    13 #include <stack>
    14 #include <queue>
    15 #include <algorithm> 
    16 #include <functional>
    17 #include <map>
    18 #include <set> 
    19 #include <cctype>
    20 #include <unordered_map>
    21 #include <unordered_set>
    22 #include <memory> 
    23 #include <new> 
    24  
    25 using namespace std;
    26 using namespace std::placeholders;
    27 
    28 void func()
    29 {
    30     allocator<string> a;
    31     auto const pa = a.allocate(5);    //pa指向a分配的内存首部 
    32     auto q = pa;
    33     string s;
    34     while (q != pa + 5 && cin >> s) {
    35         a.construct(q++, s);
    36     }
    37     //q指向最后构造的元素之后的位置 
    38     while (q != pa) {
    39         --q;
    40         cout << *q << endl;
    41         a.destroy(q);        //销毁元素 
    42     }
    43     a.deallocate(pa, 5);     //释放内存 
    44 }
    45 
    46 int main()
    47 {
    48     func();
    49     return 0;
    50 }
    View Code

    12.27~12.28

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <memory>
    #include <map>
    #include <set>
    #include <vector>
    #include <string>
    
    using namespace std; 
    
    class QueryResult;
    //保存输入文件 
    class TextQuery {
    	using lineNo = vector<string>::size_type;
    public:
    	TextQuery(ifstream &is);
    	QueryResult query(const string&) const;
    private:
    	shared_ptr<vector<string>> file;
    	map<string, shared_ptr<set<lineNo>>> imap;
    };
    
    //保存查询结果 
    class QueryResult {
    	using lineNo = vector<string>::size_type;
    	friend ostream& operator<<(ostream&, const QueryResult&);
    public:
    	QueryResult(const string &s, shared_ptr<vector<string>> f, shared_ptr<set<lineNo>> l) :sword(s), file(f), line(l) {}
    private:
    	string sword;
    	shared_ptr<vector<string>> file;
    	shared_ptr<set<lineNo>> line;
    };
    
    TextQuery::TextQuery(ifstream &is) :file(make_shared<vector<string>>())
    {
    	string line;
    	while (getline(is, line)) {
    		file->push_back(line);
    		istringstream in(line);
    		auto l = file->size() - 1;
    		string word;
    		while (in >> word) {
    			shared_ptr<set<lineNo>> &r = imap[word];
    			if (!r)
    				r.reset(new set<lineNo>);
    			r->insert(l);
    		}
    	}
    }
    
    QueryResult TextQuery::query(const string &word) const
    {
    	static shared_ptr<set<lineNo>> nodata(new set<lineNo>);
    	auto it = imap.find(word);
    	if (it != imap.end())
    		return QueryResult(word, file, it->second);
    	else
    		return QueryResult(word, file, nodata);
    }
    
    ostream& operator<<(ostream &os, const QueryResult &qr)
    {
    	auto cnt = qr.line->size();
    	os << qr.sword << " occurs " << cnt << (cnt > 1 ? " times" : " time") << endl;
    	for (auto l : *qr.line) {
    		os << "	(line " << l + 1 << ") " << *(qr.file->begin() + l) << endl; 
    	}
    	return os;
    }
    
    int main()  
    {  
    	ifstream in("data.txt");
    	TextQuery tq(in);
    	cout << "请输入要查询的单词:
    ";
    	string s;
    	while (cin >> s) {
    		cout << tq.query(s) << endl;
    		cout << "请输入要查询的单词:
    ";
    	}
    	return 0;
    }

    12.29

    do {  
         cout<<"enter word to look for ,or q to quit: ";  
         string s;  
         if (!(cin>>s) || s == "q") break;  
         query_and_print(s, cout)<<endl;  
    } while (true); 
    

    12.30

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <iterator>
    #include <vector> 
    #include <string>
    #include <algorithm> 
    #include <map>
    #include <set> 
    #include <memory> 
     
    using namespace std;
    
    using line_no = vector<string>::size_type;
    
    class QueryResult; 
    class TextQuery {
    public:
    	TextQuery(ifstream &is);
    	QueryResult query(const string &word) const;
    private:
    	shared_ptr<vector<string>> file;
    	map<string, shared_ptr<set<line_no>>> pm;
    };
    
    //考验你对关联容器和shared_ptr的掌握 
    TextQuery::TextQuery(ifstream &is): file(new vector<string>)
    {
    	string line;
    	while (getline(is, line)) {
    		file->push_back(line);
    		int lineNo = file->size() - 1;		//当前行号 
    		istringstream in(line);
    		string word;
    		while (in >> word) {
    			shared_ptr<set<line_no>> &lines = pm[word];
    			if (!lines)				//若map中无此单词 
    				lines.reset(new set<line_no>);	//分配一个新set 
    			lines->insert(lineNo);
    		}
    	}
    }
    
    class QueryResult {
    	friend ostream& print(ostream &os, const QueryResult &qr);
    public:
    	QueryResult(string s, shared_ptr<vector<string>> f, shared_ptr<set<line_no>> p):
    		sought(s), file(f), lines(p) {}
    private:
    	string sought;							//查询的单词 
    	shared_ptr<vector<string>> file;		//文件内容 
    	shared_ptr<set<line_no>> lines;			//出现的行号 
    };
    
    QueryResult TextQuery::query(const string &word) const
    {
    	static shared_ptr<set<line_no>> nodata(new set<line_no>);
    	auto ans = pm.find(word);
    	if (ans == pm.end())
    		return QueryResult(word, file, nodata);
    	else
    		return QueryResult(word, file, ans->second);
    } 
    
    string make_plural(size_t cnt, const string &s1, const string &s2)
    {
        return cnt > 1 ? s1 + s2 : s1;
    }
    
    ostream& print(ostream &os, const QueryResult &qr)
    {
    	os << qr.sought << " occurs " << qr.lines->size() << " " 
    	   << make_plural(qr.lines->size(), "time", "s") << endl;
        //打印单词的每一行
        for (auto num : *qr.lines)
            //避免行号从0开始给用户带来的困惑
            os << "	(line " << num + 1 << ")" << *(qr.file->begin() + num) << endl;
        return os;
    }
    
    void runQueries(ifstream &infile)
    {
        TextQuery tq(infile);
        while (true) {
            cout << "Enter word to look for, or q to quit: ";
            string s;
            if (!(cin >> s) || s == "q")  break;
            print(cout, tq.query(s));
            cout << endl;
        }
    }
     
    int main()
    {
        ifstream in("data.txt");
        runQueries(in);
        return 0;
    }

    12.31

    vector会保存相同的行号,故可能会打印同一行多次。

    12.32

    /*	StrBlob.h	*/
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <string>
    #include <map>
    #include <set>
    #include <memory>
    #include <stdexcept>
    #include <initializer_list>
    
    using namespace std;
    
    class StrBlob {
    public:
    	using size_type = vector<string>::size_type;
    	StrBlob();
    	StrBlob(initializer_list<string> il);
    	StrBlob(vector<string> *p) :data(p) {}
    	size_type size() const { return data->size(); }
    	bool empty() const { return data->empty(); }
    	void push_back(const string &s);
    	void pop_back();
    	//返回string的引用,是因为调用点会使用该string
    	//如b.front() = "first"; 
    	string& front();
    	string& back();
    	//只有const StrBlob对象才会调用以下函数 
    	const string& front() const;
    	const string& back() const;
    	vector<string>::iterator begin() const { return data->begin(); }
    private:
    	shared_ptr<vector<string>> data;
    	void check(size_type i, const string &msg) const; 
    }; 
    
    StrBlob::StrBlob(): data(make_shared<vector<string>>())
    {
    }
    
    StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il))
    {	
    }
    
    void StrBlob::check(size_type i, const string &msg) const
    {
    	if (i >= data->size())
    		throw out_of_range(msg);
    }
    
    void StrBlob::push_back(const string &s)
    {
    	data->push_back(s);
    }
    
    void StrBlob::pop_back()
    {
    	check(0, "此StrBlob对象指向一个空vector!
    ");
    	data->pop_back();
    }
    
    string& StrBlob::front()
    {
    	check(0, "此StrBlob对象指向一个空vector!
    ");
    	return data->front();
    }
    
    string& StrBlob::back()
    {
    	check(0, "此StrBlob对象指向一个空vector!
    ");
    	return data->back();
    }
    
    const string& StrBlob::front() const
    {
    	check(0, "此StrBlob对象指向一个空vector!
    ");
    	cout << "调用对象为const StrBlob!
    ";
    	return data->front();
    }
    
    const string& StrBlob::back() const
    {
    	check(0, "此StrBlob对象指向一个空vector!
    ");
    	cout << "调用对象为const StrBlob!
    ";
    	return data->back();
    }
    
    /*	TextQuery.h	*/
    #include "StrBlob.h"
    using lineNo = vector<string>::size_type;
    
    class QueryResult;
    class TextQuery {
    public:
    	TextQuery(ifstream&);
    	QueryResult query(const string&) const;
    private:
    	StrBlob file;
    	map<string, shared_ptr<set<lineNo>>> imap; 
    };
    
    class QueryResult {
    	friend ostream& operator<<(ostream&, const QueryResult&);
    public:
    	QueryResult(const string &s, StrBlob f, shared_ptr<set<lineNo>> l)
    		:qrword(s), qrfile(f), qrline(l) {}
    private:
    	string qrword;
    	StrBlob qrfile;
    	shared_ptr<set<lineNo>> qrline;
    };
    
    //TextQuery::TextQuery(ifstream &in)		//此情况以默认构造函数构造一个空vector<string>
    TextQuery::TextQuery(ifstream &in) :file(new vector<string>)
    {
    	string line;
    	while (getline(in, line)) {
    		file.push_back(line);
    		int rowNo = file.size() - 1;
    		istringstream is(line);
    		string word;
    		while (is >> word) {
    			shared_ptr<set<lineNo>> &r = imap[word];
    			if (!r)
    				r.reset(new set<lineNo>);
    			r->insert(rowNo);
    		}
    	}
    }
    
    QueryResult TextQuery::query(const string &word) const
    {
    	static shared_ptr<set<lineNo>> nodata(new set<lineNo>);
    	auto it = imap.find(word);
    	if (it == imap.end())
    		return QueryResult(word, file, nodata);
    	else
    		return QueryResult(word, file, it->second);
    }
    
    ostream& operator<<(ostream &os, const QueryResult &qr)
    {
    	int cnt = qr.qrline->size();
    	os << qr.qrword << " occurs " << cnt << (cnt > 1 ? " times" : " time") << endl;
    	for (auto &line : *qr.qrline)
    		os << "	(line " << line << ") " << *(qr.qrfile.begin() + line) << endl;
    	return os;
    }
    
    #include "TextQuery.h"
    
    int main()
    {
    	string fileName; 
    	cin >> fileName;
    	ifstream in;
    	in.open(fileName);
    	if (!in) {
    		cerr << "No such file!
    ";
    		return -1;
    	}
    	TextQuery tq(in);
    	cout << "请输入要查询的单词:
    ";
    	string word;
    	while (cin >> word) {
    		cout << tq.query(word) << endl;
    		cout << "请输入要查询的单词:
    ";
    	}
    	in.close();
    }
    

     

    12.33

    class QueryResult {
    	using lineNo = vector<string>::size_type;
    	friend ostream& operator<<(ostream&, const QueryResult&);
    public:
    	QueryResult(const string &s, shared_ptr<vector<string>> f, shared_ptr<set<lineNo>> l) :qrword(s), qrfile(f), qrline(l) {}
    	set<lineNo>::iterator begin() const { return qrline->begin(); }
    	set<lineNo>::iterator end() const { return qrline->end(); }
    	shared_ptr<vector<string>> get_file() const { return qrfile; }
    private:
    	string qrword;
    	shared_ptr<vector<string>> qrfile;
    	shared_ptr<set<lineNo>> qrline;
    };

     

  • 相关阅读:
    态度决定你的人生高度(一个人能否成功,就看他的态度)
    要取得成功,必须有所牺牲:职场超级成功秘诀
    28位世界名人得到过的最佳忠告(仔细体味,获益匪浅)
    你可知道
    不要把失败的责任推给你的命运,你距离你的目标有多远
    一个人凭什么自信?认识自我—你就是一座金矿
    试一下,把你的生命折叠51次 相信你会得到成功的厚度
    赠鹰飞道扬(帮别人名字作诗)
    魏海燕(帮别人名字作诗)
    职场有感
  • 原文地址:https://www.cnblogs.com/xzxl/p/7706088.html
Copyright © 2011-2022 走看看