womewomenvector的构造函数和string的构造函数模拟实现类似,但也有不同
(1) 默认构造函数
(2) 通过存放数据的个数来初始化
(3) 通过迭代器初始化
(4) 通过对象初始化(拷贝构造)
目录
一、类的基本框架
二、迭代器、size()、capacity()实现
三、构造函数
1、默认构造函数
2、输入开辟的元素个数,根据元素个数开辟空间
3、通过迭代器初始化
(1) 扩容 reserve
(2) 插入 push_back
(3) 构造函数:迭代器初始化
4、通过对象初始化(拷贝构造)
(1) swap函数
(2) 拷贝构造函数
_start:空间的起始地址 _end:最后一个有效字符的下一个位置的地址
_endofstorage:空间的结束地址
我们经常可以看到下面两种写法,这就决定了,vector的数据类型不是单一的,我们需要借助类模板来实现
vector veci;
vector< vector > vecv;
namespace xing
{
template //vector容器内的数据类型不是单一的
class vector
{
typedef T* iterator;
private:
iterator _start; //起始位置
iterator _end; //数据的结束位置
iterator _endofstorage; //容器的结束位置,也就是有效数据的容量大小
};
}
和前面string类的实现不同,vector通过地址来管理数据,我们无法像前面那样直接获取数据
迭代器可以看作是 指针类型,如果vector存放的是 int 类型的数据,那么迭代器可以看作是int*指针
iterator begin()
{
return _start;
}
iterator end()
{
return _end;
}
int size()
{
return _end - _start;
}
int capacity()
{
return _endofstorage - _start;
}
这里不像前面string类一样,就算创建一个空的对象,也需要开辟一个空间存放 \0
一开始的时候,我们无需开辟空间;等到有数据输入的时候,再开辟空间
vector()
:_start(nullptr),
_end(nullptr),
_endofstorage(nullptr)
{
}
尽管string输入的是字符串,最终还是会计算字符个数,并以此来开辟空间
vector(int n, const T& val = T())
:_start(new T[n]), //开辟n个空间
_end(_start + n),
_endofstorage(_end)
{
T* finish = _start; //给空间内的每个元素赋值
while(finish != _end)
{
*finish = val;
finish++;
}
}
注意:
T val = T() 是通用的初始化方式
内置类型也可以这么赋值
int a = int(); //等价于 int a = 0
int b = int(5); //等价于 int b = 5
char c = char(); //等价于 char c = 0
前面说了,迭代器可以看作是 指针,迭代器初始化就是给定其他 vector 对象的起始位置和结束位置,以此来初始化
vector v1(10,1);
vector v2(v1.begin() , v2.end());
迭代器初始化时,参数一般会使用模板,因为类型之间可以相互转化
vector v3(10, 0);
vector v4(v3.begin(), v3.end());
所以初始框架如下:
template
vector(InputIterator first, InputIterator last)
:_start(nullptr),
_end(nullptr),
_endofstorage(nullptr)
{
}
在实际开始之前,我们需要事先准备一些要用的函数,扩容函数reserve、插入函数push_back
注意reserve和resize的区别
void reserve(int n)
{
if (n > capacity())
{
T* tmp = new T[n];
memcpy(tmp, _start, size() * sizeof(T)); //开辟一个空间tmp,并把数据拷贝到tmp里面
int len = size(); //需要事先记录下原有的数据长度
_start = tmp;
_end = _start + len; //改变的只是容量大小,实际数据长度不变
_endofstorage = _start + n;
}
}
void push_back(const T& val)
{
//判断是否需要扩容
if (_end == _endofstorage)
{
reserve(_start == nullptr ? 4 : capacity() * 2);
}
*_end = val;
_end++; //实际数据个数加 1
}
template
vector(InputIterator first, InputIterator last)
:_start(nullptr),
_end(nullptr),
_endofstorage(nullptr)
{
reserve(last - first); //先扩容
while (first != last)
{
push_back(*first); //逐个添加元素
first++;
}
}
代码测试:
int main()
{
xing::vector v3(10, 0);
xing::vector v4(v3.begin(), v3.end());
return 0;
}
这里就和string 类似了,详情可以参考下面博客中的拷贝构造函数部分
string类的模拟实现(一)—— 构造函数(无参、拷贝等)_abs(ln(1+NaN))的博客-CSDN博客https://blog.csdn.net/challenglistic/article/details/123169009?spm=1001.2014.3001.5501
void swap(vector& v1, vector& v2)
{
std::swap(v1._start, v2._start);
std::swap(v1._end, v2._end);
std::swap(v1._endofstorage , v2._endofstorage);
}
vector(vector& v)
{
vector tmp(v.begin(), v.end());
swap(*this, tmp);
}