c++定义一个成员为String的Vector

自定义一个简化版的vector

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
#ifndef STR_VEC
#define STR_VEC

#include<string>
#include<memory>
#include<iostream>
#include<initializer_list>
using std::string;

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

void push_back(const string &);
size_t size() const{return first_free-elements;}
size_t capacity() const{return cap-elements;}
string* begin() const{return elements;}
string* end() const{return first_free;}

string& at(size_t pos){return *(elements+pos);}
const string& at(size_t pos) const{return *(elements+pos);}
void resize(size_t count);
void resize(size_t count, const string&);
void reserve(size_t new_cap);
private:
static std::allocator<string> alloc;
void chk_n_alloc();
std::pair<string*, string*> alloc_n_copy(const string*, const string*);
void alloc_n_move(size_t new_cap);
void range_initialize(const string*, const string*);
void free(); //销毁元素并释放内存
void reallocate(); //获取更多内存并拷贝已有元素
string *elements; //指向数组首元素的指针
string *first_free; //指向数组第一个空闲元素的指针
string *cap; //指向数组尾后位置的指针
};
std::allocator<string> StrVec::alloc;
#endif
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
#include "StrVec.hpp"
#include<iostream>

void StrVec::chk_n_alloc()
{
std::cout<<"the size:"<<size()<<" the capacity:"<<capacity()<<std::endl;
if (size() == capacity())
{
reallocate();
std::cout<<"reallocate"<<std::endl;
}
}

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

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

void StrVec::free()
{
if(elements)
{
for(auto p = first_free; p != elements; )
alloc.destroy(--p);
}
//for_each(elements, first_free,[this](string &rhs){alloc.destroy(&rhs);});
alloc.deallocate(elements,cap-elements);
}

StrVec::StrVec(const StrVec &s)
{
range_initialize(s.begin(), s.end());
}

StrVec::StrVec(std::initializer_list<string>il)
{
range_initialize(il.begin(), il.end());
//il.begin()返回il中指向第一个元素的指针,il.end()返回il中指向最后一个元素最后元素的指针
}

void StrVec::range_initialize(const string* be, const string *en)
{
auto new_data = alloc_n_copy(be, en);
elements = new_data.first;
first_free = cap = new_data.first;
}
StrVec::~StrVec(){free();}

StrVec& StrVec::operator=(const StrVec& rhs)
{
if(this != &rhs)
{
auto new_data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = new_data.first;
first_free = cap = new_data.first;
return *this;
}
}

StrVec::StrVec(StrVec && s)noexcept:elements(s.elements),first_free(s.first_free),cap(s.cap)
{
s.elements = s.first_free = s.cap = nullptr;
}

StrVec& StrVec::operator=(StrVec &&rhs)noexcept
{
if(this != &rhs)
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
void StrVec::alloc_n_move(size_t new_cap)
{
auto new_data = alloc.allocate(new_cap);
auto dest = new_data;
auto elem = elements;
for(; elem != first_free;)
alloc.construct(dest++, std::move(*elem++));
free();
elements = new_data;
first_free = dest;
cap = new_data + new_cap;
}
void StrVec::reallocate()
{
auto new_capacity = size() ? size()*2 : 1;
alloc_n_move(new_capacity);
std::cout<<"after reallocate,size: "<<size()<<", capacity:"<<capacity()<<std::endl;
}

void StrVec::reserve(size_t new_cap)
{
if(capacity() < new_cap)
alloc_n_move(new_cap);
}

void StrVec::resize(size_t count)
{
resize(count,string());
}

void StrVec::resize(size_t count, const string &s)
{
if(count > size())
{
if(count > capacity()) reserve(count*2);
for(size_t i = size(); i != count; i++)
alloc.construct(first_free++,s);
}
else if(count < size())
{
while(first_free != elements+count)
{
alloc.destroy(--first_free);
}
}
}