一.每个代码几乎都有详细注释(后附测试结果)
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <stdexcept>
#include <cmath>
#include <cassert>
#include <fstream>
#include <sstream>
#include <deque>
#include <list>
#include <algorithm>
#include <numeric>
#include <functional>
#include <map>
#include <memory>
#include <cstring>
#include <set>
using namespace std;
class strVec
{
public:
strVec() : elements(nullptr), frist_free(nullptr), cap(nullptr) {} //默认构造
strVec(const strVec &); //拷贝构造
strVec &operator=(const strVec &); //拷贝赋值运算符
~strVec(); //析构函数
void push_back(const string &); // push_back 函数
size_t size() const { return frist_free - elements; }
size_t capcity() const { return cap - elements; }
string *begin() const { return elements; }
string *end() const { return frist_free; }
void reserve(size_t &);
void resize(size_t &);
private:
static allocator<string> alloc;
pair<string *, string *> alloc_n_copy(const string *, const string *);
void chk_n_alloc() //如果内存空间不够,分配内存空间
{
if (size() == capcity()) //如果元素数量==容器容量
reallocate(); //重新分配内存空间
}
void free(); // destroy掉元素然后释放内存空间
void reallocate(); //重新分配内存空间
string *elements; //指向分配的内存中的首位置
string *frist_free; //指向分配的内存中第一个空闲位置(类似end())
string *cap; //指向分配的内存中最后一个空闲位置的后一个位置
};
allocator<string> strVec::alloc; //分配元素的
void strVec::push_back(const string &s)
{
chk_n_alloc();
alloc.construct(frist_free++, s); // first_free先被插入后递增,待s插入后依然指向第一个空闲空间
}
pair<string *, string *>
strVec::alloc_n_copy(const string *a, const string *b) //拷贝构造,拷贝赋值时会用到,
{
auto data = alloc.allocate(b - a); //分配与给定范围一样大的内存空间,用data来暂时接收(data未初始化)
return {data, uninitialized_copy(a, b, data)}; //返回一个pair对组,将(a,b)范围的元素拷贝至未初始化的内存空间里
}
void strVec::free() //销毁内容 ,然后释放分配的内存空间
{
if (elements) //判断内存空间元素是否为空
{
for (auto i = frist_free; i != elements;) //逆序循环遍历元素
{
alloc.destroy(--i); //依次销毁元素
}
alloc.deallocate(elements, cap - elements); //释放分配的内存空间(析构函数用的上)
}
}
strVec::strVec(const strVec &s1) //定义拷贝构造函数
{
auto newdata = alloc_n_copy(s1.begin(), s1.end()); //分配内存,将s1里的所有元素拷贝到新分配的内存空间
free(); //销毁原有内存空间
elements = newdata.first; //将newdata的元素 “从首元素开始依次存放” 当前内存空间中
frist_free = cap = newdata.second; // newdata.second返回指向最后一个构造元素之后的位置
}
strVec::~strVec() //定义析构函数
{
free(); //直接调用free()先销毁所有元素在释放分配的所有内存
}
strVec &strVec::operator=(const strVec &s)
{
auto newdata = alloc_n_copy(s.begin(), s.end()); //分配内存,将s1里的所有元素拷贝到新分配的内存空间
free(); //销毁原有内存空间
elements = newdata.first; //将newdata的元素 “从首元素开始依次存放” 当前内存空间中
frist_free = cap = newdata.second; // newdata.second返回指向最后一个构造元素之后的位置
return *this; //返回调用者本身
}
void strVec::reallocate()
{
if (size() == capcity())
{
auto newcapcity=size() ? 2 * size() : 1;
auto newdata = alloc.allocate(newcapcity); //分配两倍size()大小的内存空间
auto dest = newdata; //指向新空间的下一个空闲位置
auto elem = elements; //指向当前旧空间第一个元素
for (decltype(size()) i = 0; i < size(); ++i)
{
alloc.construct(dest++, move(*elem++)); //将接引用的elem递增依次加入到新分配的数组中
}
free(); //移动完成后释放原有数组内存空间
elements = newdata; //赋予首地址,也就是指向新空间第一个元素
frist_free = dest; // dest经过一系列递增后指向新空间的第一个空闲元素;
cap = newcapcity+ elements; //新空间容量
}
}
void strVec::reserve(size_t &s)
{
if (s <= size()) //如果新空间<=当前存在元素的空间
{
return; //直接返回
}
else if (s > size()) //如果新空间大于当前存在有元素的空间
{
auto newdata = alloc.allocate(s); //分配两倍size()大小的内存空间
auto dest = newdata; //指向新空间的下一个空闲位置
auto elem = elements; //指向当前旧空间第一个元素
for (decltype(size()) i = 0; i < size(); ++i)
{
alloc.construct(dest++, move(*elem++)); //将接引用的elem递增依次加入到新分配的数组中
}
free(); //移动完成后释放原有数组内存空间
elements = newdata; //赋予首地址,也就是指向新空间第一个元素
frist_free = dest; // dest经过一系列递增后指向新空间的第一个空闲元素;
cap = s + elements; //新空间容量
}
}
void strVec::resize(size_t &s) //改变初始化的元素数量
{
if (s > size()) //如果s>size()需要将s大小范围的内存空间全都初始化
{
auto newfrist_free = frist_free;
for (size_t i = size(); i < s; ++i)
alloc.construct(newfrist_free++, " "); //将多出来的几个内存空间用" "初始化
frist_free = newfrist_free; //更新新的空闲空间
return;
}
if (s > capcity()) //如果s的值大于capcity那么需要重新分配空间,并且要将所有元素都初始化
{
auto newdata = alloc.allocate(s); //分配s大小的内存空间
auto dest = newdata; //指向新空间的下一个空闲位置
auto elem = elements; //指向当前旧空间第一个元素
auto oldsize = size(); // b保存旧空间元素大小
for (decltype(size()) i = 0; i < size(); ++i)
{
alloc.construct(dest++, move(*elem++)); //将解引用的elem递增依次加入到新分配的数组中
}
free(); //移动完成后释放原有数组内存空间
elements = newdata; //赋予首地址,也就是指向新空间第一个元素
frist_free = dest; // dest经过一系列递增后指向新空间的第一个空闲元素;
cap = 2 * size() + elements; //新空间容量
auto newfrist_free = frist_free;
for (size_t i = oldsize; i < s; ++i)
alloc.construct(newfrist_free++, " "); //将剩下的没有元素的内存空间用" "初始化
frist_free = newfrist_free; //更新新的空闲空间
return;
}
if (s < size())
{
auto newfrist_free = frist_free;
for (size_t i = 0; i < size() - s; ++i)
alloc.destroy(--newfrist_free);
frist_free = newfrist_free;
return;
}
if(s==size())
return;
}
int main()
{
strVec s;
string s1="abc";
s.push_back(s1);//添加第一个元素
string s2="def";
s.push_back(s2);//添加第二个元素
cout<<*(s.begin())<<endl;//输出第一个元素
cout<<s.size()<<endl;//输出内存中有多少元素
size_t a=1;
s.resize(a); //resize<size()情况
cout<<s.size()<<endl;//输出内存中元素数量
size_t b=10;
s.resize(b); //resize>size()情况
cout<<s.size()<<endl;//输出内存中元素数量
size_t c=20;
s.reserve(c);
cout<<s.capcity()<<endl;//输出
return 0;
}
二.测试结果