C++primer 13.5节练习

练习13.39

 1 #include <iostream>
 2 #include <string>
 3 #include <utility>
 4 #include <memory>
 5
 6 using namespace std;
 7
 8 class StrVec {
 9 public:
10     StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
11     StrVec(const StrVec&);
12     StrVec& operator=(const StrVec&);
13     ~StrVec();
14     void push_back(const string &);
15     size_t size() const { return first_free - elements; }
16     size_t capacity() const { return cap - elements; }
17     string *begin() const { return elements; }
18     string *end() const { return first_free; }
19 private:
20     string *elements;
21     string *first_free;
22     string *cap;
23     pair<string *, string *> alloc_n_copy(const string *, const string *);
24     void chk_n_alloc() { if (size() == capacity()) reallocate(); }
25     static allocator<string> alloc;
26     void free();
27     void reallocate();
28 };
29
30 int main()
31 {
32     system("pause");
33     return 0;
34 }
35
36 StrVec::StrVec(const StrVec &s)
37 {
38     auto newdata = alloc_n_copy(s.begin(), s.end());
39     elements = newdata.first;
40     first_free = cap = newdata.second;
41 }
42
43 StrVec & StrVec::operator=(const StrVec &rhs)
44 {
45     auto data = alloc_n_copy(rhs.begin(), rhs.end());
46     free();
47     elements = data.first;
48     first_free = cap = data.second;
49     return *this;
50 }
51
52 StrVec::~StrVec()
53 {
54     free();
55 }
56
57 void StrVec::push_back(const string &s)
58 {
59     chk_n_alloc();
60     alloc.construct(first_free++, s);
61 }
62
63 pair<string*, string*> StrVec::alloc_n_copy(const string *b, const string *e)
64 {
65     auto data = alloc.allocate(e - b);
66     return{ data,uninitialized_copy(b,e,data) };
67 }
68
69 void StrVec::free()
70 {
71     if (elements)
72     {
73         for (auto p = first_free; p != elements;)
74             alloc.destroy(--p);
75         alloc.deallocate(elements, cap - elements);
76     }
77 }
78
79 void StrVec::reallocate()
80 {
81     auto newcapacity = size() ? 2 * size() : 1;
82     auto newdata = alloc.allocate(newcapacity);
83     auto dest = newdata;
84     auto elem = elements;
85     for (size_t i = 0; i != size(); ++i)
86         alloc.construct(++dest, std::move(*elem++));
87     free();
88     elements = newdata;
89     first_free = dest;
90     cap = elements + newcapacity;
91 }

练习13.40

  1 #include <iostream>
  2 #include <string>
  3 #include <utility>
  4 #include <memory>
  5
  6 using namespace std;
  7
  8 class StrVec {
  9 public:
 10     StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
 11     StrVec(const initializer_list<string> &s);
 12     StrVec(const StrVec&);
 13     StrVec& operator=(const StrVec&);
 14     ~StrVec();
 15     void push_back(const string &);
 16     size_t size() const { return first_free - elements; }
 17     size_t capacity() const { return cap - elements; }
 18     string *begin() const { return elements; }
 19     string *end() const { return first_free; }
 20     void resize(size_t n, const string&);
 21     void Reserve(const size_t& len);//重新分配大小
 22 private:
 23     string *elements;
 24     string *first_free;
 25     string *cap;
 26     pair<string *, string *> alloc_n_copy(const string *, const string *);
 27     void chk_n_alloc() { if (size() == capacity()) reallocate(); }
 28     static allocator<string> alloc;
 29     void free();
 30     void reallocate();
 31 };
 32
 33 int main()
 34 {
 35     system("pause");
 36     return 0;
 37 }
 38
 39 StrVec::StrVec(const initializer_list<string>& s)
 40 {
 41     auto newzone = alloc_n_copy(s.begin(), s.end());
 42     elements = newzone.first;
 43     first_free = cap = newzone.second;
 44 }
 45
 46 /*StrVec(const initializer_list<string> &vs)
 47 {
 48     elements = nullptr;
 49     first_free = nullptr;
 50     cap = nullptr;
 51     for (auto it : vs)
 52         this->Push_back(it);
 53 }*/            //这两种都行应该
 54
 55 StrVec::StrVec(const StrVec &s)
 56 {
 57     auto newdata = alloc_n_copy(s.begin(), s.end());
 58     elements = newdata.first;
 59     first_free = cap = newdata.second;
 60 }
 61
 62 StrVec & StrVec::operator=(const StrVec &rhs)
 63 {
 64     auto data = alloc_n_copy(rhs.begin(), rhs.end());
 65     free();
 66     elements = data.first;
 67     first_free = cap = data.second;
 68     return *this;
 69 }
 70
 71 StrVec::~StrVec()
 72 {
 73     free();
 74 }
 75
 76 void StrVec::push_back(const string &s)
 77 {
 78     chk_n_alloc();
 79     alloc.construct(first_free++, s);
 80 }
 81
 82 void StrVec::resize(size_t n, const string &s)
 83 {
 84     if (n == size())
 85         return;
 86     else if (n > size())
 87     {
 88         if (n > capacity())
 89         {
 90             Reserve(n);
 91             for (auto i = 0; i != n - size();)
 92                 alloc.construct(first_free++, s);
 93         }
 94         else
 95         {
 96             for (auto i = 0; i != n - size();)
 97                 alloc.construct(first_free++, s);
 98         }
 99     }
100     else
101     {
102         auto flag = first_free;
103         while (first_free - elements != n)
104             alloc.destroy(--first_free);
105         alloc.deallocate(flag, size() - n);
106     }
107 }
108
109 pair<string*, string*> StrVec::alloc_n_copy(const string *b, const string *e)
110 {
111     auto data = alloc.allocate(e - b);
112     return{ data,uninitialized_copy(b,e,data) };
113 }
114
115 void StrVec::free()
116 {
117     if (elements)
118     {
119         for (auto p = first_free; p != elements;)
120             alloc.destroy(--p);
121         alloc.deallocate(elements, cap - elements);
122     }
123 }
124
125 void StrVec::reallocate()
126 {
127     auto newcapacity = size() ? 2 * size() : 1;
128     auto newdata = alloc.allocate(newcapacity);
129     auto dest = newdata;
130     auto elem = elements;
131     for (size_t i = 0; i != size(); ++i)
132         alloc.construct(++dest, std::move(*elem++));
133     free();
134     elements = newdata;
135     first_free = dest;
136     cap = elements + newcapacity;
137 }
138
139 void StrVec::Reserve(const size_t& len)//重新分配大小
140 {
141     if (len <= cap - elements)//小于或等于不申请
142         return;
143     //未构造的内存减少
144     auto newcapacity = len;
145     auto newdata = alloc.allocate(newcapacity);//申请len倍内存
146     auto dest = newdata;//alloc返回的首指针
147     auto elem = elements;
148     for (size_t i = 0;i != size();++i)
149         alloc.construct(dest++, move(*elem++));
150     free();
151     elements = newdata;//新的首指针
152     first_free = dest;
153     cap = elements + newcapacity;
154 }

练习13.41

因为first_free所指的位置是最后一个存放元素后一个位置,所以应该用后置递增运算,这样就能依次的进行添加,如果用前置,中间会空出一个内存,这种情况是未定义的;

练习13.42

将原先的代码的vector模板改为StrVec类就可以了

练习13.43

 1 void StrVec::free()
 2 {
 3     if (elements)
 4     {
 5         for_each(elements, first_free, [this](string &p) { alloc.destroy(&p);});
 6         /*for (auto p = first_free; p != elements;)
 7             alloc.destroy(--p);*/
 8         alloc.deallocate(elements, cap - elements);
 9     }
10 }

练习13.44

 1 #include <iostream>
 2 #include <string>
 3 #include <utility>
 4 #include <memory>
 5 #include <algorithm>
 6
 7 using namespace std;
 8
 9 class String {
10     friend ostream &print(ostream &os, String &s);
11 public:
12     String(): element(nullptr), first_free(nullptr) {}
13     String(char *);
14 private:
15     static allocator<char> alloc;
16     char *element;
17     char *first_free;
18 };
19 allocator<char> String::alloc;
20 ostream &print(ostream &os, String &s);
21
22 int main()
23 {
24     String s1;
25     String s2("hello");
26     String s3("hello world");
27     print(cout, s1);
28     print(cout, s2);
29     print(cout, s3);
30     system("pause");
31     return 0;
32 }
33
34 String::String(char *s)
35 {
36     int i = 0;
37     while (s[i] != ‘\0‘)
38         ++i;
39     auto newloc = alloc.allocate(i);
40     auto dest = newloc;
41     for (auto count = 0; count != i;++count)
42         alloc.construct(dest++, s[count]);
43     element = newloc;
44     first_free = dest;
45 }
46
47 ostream & print(ostream &os,String &s)
48 {
49     while (s.element != s.first_free)
50     {
51         os << *(s.element);
52         s.element++;
53     }
54     cout << endl;
55     return os;
56     // TODO: 在此处插入 return 语句
57 }
时间: 2024-08-27 09:42:37

C++primer 13.5节练习的相关文章

C++primer 13.2节练习

练习13.22 1 #include <iostream> 2 #include <string> 3 #include <memory> 4 5 using namespace std; 6 7 8 class HasPtr { 9 friend ostream &print(ostream &os, HasPtr &h); 10 public: 11 HasPtr(const string &s = string()) : ps(s)

C++primer 13.3节练习

练习13.29 不会,因为该类中的数据成员都是内置类型的,而内置类型是没有特定版本的swap的,所以对swap的调用会调用标准库的std::swap: 练习13.30 1 #include <iostream> 2 #include <string> 3 #include <memory> 4 5 using namespace std; 6 7 8 class HasPtr { 9 friend ostream &print(ostream &os,

C++primer 13.1.3节练习

练习13.9 析构函数执行与构造函数相反的操作,构造函数初始化对象的非static数据成员,析构函数释放对象使用的资源,并销毁对象的非static数据成员.当一个类没有定义自己的析构函数的时候,编译器会为它定义一个合成析构函数. 练习13.10 在一个构造函数中,成员的初始化是在函数体执行之前完成的,且按照他们再类中出现的顺序进行初始化.再一个析构函数中,首先执行函数体,然后销毁成员.成员按照初始化顺序的逆序销毁. 练习13.11 1 #include <iostream> 2 #includ

C++primer 13.1.2节练习

练习13.6 其实就是"="运算,也就是赋值运算.右侧运算对象作为显示参数向左侧传递时时候.合成拷贝赋值运算符来禁止该类型对象的赋值.当一个类没有定义自己的拷贝赋值运算符的时候,编译器会为它自动生成一个合成拷贝赋值运算符. 练习13.7 将一个StrBlob赋值给另一个StrBlob这个操作是完全没有问题的. 当赋值StrBlobPtr的时候就会出错,在编译的时候就会报错,左右值的类型不一样(也不是继承关系),无法完成赋值. 练习13.8 1 #include <iostream

C++primer 13.6.2节练习

练习13.49 13.50 1 #include <iostream> 2 #include <string> 3 #include <utility> 4 #include <memory> 5 #include <algorithm> 6 #include <vector> 7 8 using namespace std; 9 10 class String { 11 friend ostream &print(ostre

C++primer 13.2.1节练习

练习13.23 1 #include <iostream> 2 #include <string> 3 #include <memory> 4 5 using namespace std; 6 7 8 class HasPtr { 9 friend ostream &print(ostream &os, HasPtr &h); 10 public: 11 HasPtr(const string &s = string()) : ps(ne

C++primer 13.6.3节练习

练习13.55 1 void push_back(const string& s) &&; 练习13.56 此时拷贝一个副本,但是问题来了,ret是一个左值,返回他的sorted函数,会不停的进行递归自己,而该函数并没有一个终止条件,所以最后堆栈会溢出,导致程序异常终止: 练习13.57 此时函数返回的是一个临时对象的sorted函数,而临时对象是一个右值,这时会调用右值的sorted重载函数,程序正常运行,但是原对象依然没有排序,因为他是一个const或者是一个左值,改变的只是临

C++primer 13.1.1节练习

练习13.1 如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数:拷贝初始化通常使用拷贝构造函数来完成.拷贝构造函数被用来初始化非引用类类型参数: 练习13.2 拷贝构造函数自己的参数必须是引用类型.如果其参数不是引用类型,则调用永远也不会成功-为了调用拷贝构造函数,我们必须拷贝他的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环: 练习13.3 如果我们没有定义自己的拷贝构造函数,则会调用编译器为我们合成的拷贝构造函数 练习13.

C++primer 13.1.6节练习

练习13.18 1 #include <iostream> 2 #include <string> 3 #include <memory> 4 5 using namespace std; 6 7 static int i = 0; 8 9 class Employee { 10 friend ostream& print(ostream& os, const Employee& emp); 11 public: 12 Employee() :