动态内存管理类StrVec的实现

实现一个动态内存管理类

  1. StrBlobvector<string>可以管理元素的内存.
  2. 实现一个vector<string>

allocator<>类是分配的原始内存,当调用alloc.destroy(first_free),

  • 按道理来说destroy执行对象的析构函数,string析构函数执行完后会回收内存,再访问该string就访问越界了
  • 但是如果在destroy()后访问string指针的内容,仍可以读取到,我觉得原因在于内存是由allocator类申请来的的,由alloc对象管理,即使string对象执行完析构函数.内存也不会回收

alloc_n_copy非常巧妙

  • 在原alloc对象申请原始内存,通过uninitialized_copy()来初始化
  • 支持vector<>的部分初始化

StrVec.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#ifndef STRVEC_H
#define STRVEC_H

#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <initializer_list>
#include <algorithm>


class StrVec {
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr) {}
StrVec(std::initializer_list<std::string> i1);
StrVec(const StrVec&);
StrVec& operator=(const StrVec&);
~StrVec();
StrVec(size_t);
StrVec(size_t,const std::string&);

void resize(size_t,const std::string&);
void resize(size_t);
void reserve(size_t);
void push_back(std::string&);
void push_back(std::string);
std::string pop_back();
size_t size() const { return first_free - elements; }
size_t capacity() const { return cap - elements; }
std::string* begin() const { return elements; }
std::string* end() const { return first_free; }

private:
static std::allocator<std::string> alloc;

void chk_n_alloc();
void free();
void reallocate();
void reallocate(size_t);
std::pair<std::string*,std::string*>
alloc_n_copy(const std::string*,const std::string*);

void alloc_n_copy(size_t,const std::string&);

std::string* elements;
std::string* first_free;
std::string* cap;
};
void StrVec::free() {
/* if (elements)*/
//for (auto it = first_free; it != elements;)
/*alloc.destroy(--it);*/
if (elements)
std::for_each(elements,first_free,
[](std::string& s){ alloc.destroy(&s);});
alloc.deallocate(elements,cap - elements);
std::cout << " ~StrVec() " << std::endl;
}
void StrVec::reallocate() {
auto newcapacity = size() ? 2*size() : 1;
auto newdata = alloc.allocate(newcapacity);

auto dest = newdata;
auto elem = elements;
for (size_t i=0; i!=size(); ++i)
alloc.construct(dest++,std::move(*elem++));
free();

elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}

void StrVec::reallocate(size_t newcapacity) {
auto newdata = alloc.allocate(newcapacity);

auto dest = newdata;
auto elem = elements;
for (size_t i=0; i!=size(); ++i)
alloc.construct(dest++,std::move(*elem++));
free();

elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}

void StrVec::reserve(size_t n) {
if (n > capacity()) reallocate(n);
}
void StrVec::resize(size_t n) {
if (n > size()) {
while (size() < n)
push_back("");
} else if (n < size()) {
while (size() > n)
alloc.destroy(--first_free);
}
}
void StrVec::resize(size_t n,const std::string& s) {
if (n > size()) {
while (size() < n)
push_back(s);
}
}

void StrVec::chk_n_alloc() {
if (size() == capacity())
reallocate();
}
void StrVec::push_back(std::string& s) {
chk_n_alloc();
alloc.construct(first_free++,s);
}

void StrVec::push_back(std::string s) {
chk_n_alloc();
alloc.construct(first_free++,s);
}

std::pair<std::string*,std::string*>
StrVec::alloc_n_copy(const std::string* b,const std::string* c) {
auto data = alloc.allocate(c-b);
return {data,uninitialized_copy(b,c,data)};
}

StrVec::StrVec(const StrVec& rhs) {
auto newdata = alloc_n_copy(rhs.begin(),rhs.end());
elements = newdata.first;
cap = first_free = newdata.second;
}

void StrVec::alloc_n_copy(size_t n,const std::string& s) {
auto newdata = alloc.allocate(n);
auto dest = newdata;
for (auto i=0; i<n; ++i)
alloc.construct(dest++,s);
elements = newdata;
first_free = dest;
cap = elements + n;

}
StrVec::StrVec(size_t n) {
alloc_n_copy(n,"");
}

StrVec::StrVec(size_t n,const std::string& s) {
alloc_n_copy(n,s);
}

StrVec::~StrVec() { free(); }

StrVec& StrVec::operator=(const StrVec& rhs) {
auto data = alloc_n_copy(rhs.begin(),rhs.end());
free();
elements = data.first;
cap = first_free = data.second;
return *this;
}
StrVec::StrVec(std::initializer_list<std::string> i1) {
auto newdata = alloc_n_copy(i1.begin(),i1.end());
elements = newdata.first;
cap = first_free = newdata.second;
}
std::string StrVec::pop_back() {
if (size()>=1) {
std::string temp = *(--first_free);
alloc.destroy(first_free);
return temp;
}
}
#endif

StrVec类的使用

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include "StrVec.h"
#include <string>

std::allocator<std::string> StrVec::alloc;

int main() {
std::string test(" test string ");
StrVec temp1(10,test);
StrVec temp2 = {"a","ab","abc","abcd"};
StrVec temp3(2);
StrVec temp4 = temp2;
for (auto i:temp1)
std::cout << " i " << i << std::endl;
for (auto i:temp2)
std::cout << " i " << i << std::endl;
return 0;
}