首先打个广告,对C++后台这一块感兴趣的可以加QQ群大家可以相互学习,有问题大家也可以相互讨论,加群号码745354447。
看C++Primer看到这里的时候心里有点熟悉,因为最近也在看STL源码剖析,觉得和内存分配那一章很吻合,所以看起来很轻松,这里主要是举了一个例子实现vector的一个string的特例。
我觉得首先得从逻辑上梳理一下,
1:这里首先申明了一个构造函数,都用空指针去代替,申明一个StrVec对象后,很自然的就得朝这个对象里去加元素,那么就有push_back这个函数,那么要push_back一个元素,必须得分配内存,然后构造对象,所以就有了chk_n_alloc函数,chk_n_alloc函数首先判断vector大小和本身的capacity大小,如果最开始vector为空,则分配1个元素大小,然后后面每次加入对象的时候,内存开始以2倍扩大。分配了内存那么就要构造对像了,在STL源码剖析里分配内存和构造对象是分开的,所有后续就是构造对象。
2:复制构造函数
还是使用alloc_n_copy分配内存,然后使用uninitialized_copy构造对象
3:拷贝构造函数
拷贝构造函数首先得防止自赋值,所以得使用alloc_n_copy,然后就可以可以释放内存了,使用free函数,然后更新指针值。
完整代码:
/*#!/usr/bin/env
* ******************************************************
* Author : Gery
* Last modified: 2018-04-08 19:40
* Email : 2458314507@qq.com
* Filename : 13_39.cpp
* Description :
* ********************************************************/
#include<iostream>
#include<new>
#include<stdlib.h>
#include<algorithm>
#include<memory>
using namespace std;
class StrVec
{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}
StrVec(const StrVec&);//拷贝构造函数
StrVec &operator=(const StrVec&);//拷贝赋值运算符
~StrVec();//析构函数
void push_back(const std::string&);//拷贝元素
size_t size() const {return first_free-elements;}
size_t capacity() const {return cap-elements;}
void reserve(size_t num);
void resize(size_t num);
void resize(size_t,const string&s);
std::string *begin() const {return elements;}
std::string *end()const {return first_free;}
void cir();
private:
static std::allocator<std::string>alloc;//分配元素
//被添加元素的函数所使用
void chk_n_alloc()
{
if(size()==capacity()) reallocate();
}
//工具函数,被拷贝构造函数,赋值运算符和析构函数所使用
std::pair<std::string*,std::string*>alloc_n_copy(const std::string*,const std::string*);
void free();//销毁元素并释放内存
void reallocate();//获得更多内存并拷贝已有元素
void reallocate(size_t newcapacity);
std::string *elements;//指向数组首元素的指针
std::string *first_free;//指向数组第一个空闲元素的指针
std::string *cap;//指向数组尾后位置的指针
};
std::allocator<std::string> StrVec::alloc;
StrVec::~StrVec() { free();}
void StrVec::reserve(size_t num)
{
if(num>capacity()) reallocate(num);
}
void StrVec::resize(size_t num)
{
if(num>size())
while(size()<num) push_back("");
else if(num<size())
while(size()>num) alloc.destroy(--first_free);
}
void StrVec::resize(size_t num,const string &s)
{
if(num>size())
while(size()<num) push_back(s);
}
pair<string*,string*> StrVec::alloc_n_copy(const string *b,const string *e)
{
//分配空间保存给定范围内的元素
auto data = alloc.allocate(e-b);
//初始化并返回一个pair,该pair由data和uninitialized_copy的返回值构成
return {data,uninitialized_copy(b,e,data)};
}
StrVec &StrVec::operator=(const StrVec &rhs)//拷贝构造函数
{
auto data = alloc_n_copy(rhs.begin(),rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
StrVec::StrVec(const StrVec &rhs)
{
auto newdata = alloc_n_copy(rhs.begin(),rhs.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
void StrVec::cir()
{
for(auto p=elements;p!=first_free;p++)
cout<<*p<<endl;
}
void StrVec::push_back(const std::string&s)
{
chk_n_alloc();//确保有空间容纳新元素
alloc.construct(first_free++,s);
}
void StrVec::free()
{
//不能传递给deallocate一个空指针,如果elements为0,函数什么都不做
if(elements)//逆序销毁旧元素
{
for(auto p=first_free;p!=elements;) alloc.destroy(--p);
alloc.deallocate(elements,cap-elements);
}
}
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::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;
}
int main()
{
StrVec str;
str.push_back("fanbo");
cout<<"vector大小"<<str.size()<<" vector容量"<<str.capacity()<<endl;
str.push_back("Gery");
cout<<"vector大小"<<str.size()<<" vector容量"<<str.capacity()<<endl;
str.push_back("Kiwi");
cout<<"vector大小"<<str.size()<<" vector容量"<<str.capacity()<<endl;
str.reserve(50);
cout<<"vector大小"<<str.size()<<" vector容量"<<str.capacity()<<endl;
str.cir();
StrVec str1(str);
str1.cir();
StrVec str2 = str1;
str2.cir();
return 0;
}
最后输出为: