vector模拟实现之构造函数初始化

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模拟实现之构造函数初始化_第1张图片

  我们经常可以看到下面两种写法,这就决定了,vector的数据类型不是单一的,我们需要借助类模板来实现

vector veci;
vector< vector > vecv;
namespace xing
{
	template                //vector容器内的数据类型不是单一的
	class vector
	{
		typedef T* iterator;        
	private:
		iterator _start;            //起始位置
		iterator _end;              //数据的结束位置
		iterator _endofstorage;     //容器的结束位置,也就是有效数据的容量大小
	};
}

二、迭代器、size()、capacity()实现

和前面string类的实现不同,vector通过地址来管理数据,我们无法像前面那样直接获取数据

迭代器可以看作是 指针类型,如果vector存放的是 int 类型的数据,那么迭代器可以看作是int*指针

iterator begin()
{
	return _start;
}
iterator end()
{
	return _end;
}
int size()
{
	return _end - _start;
}
int capacity()
{
	return _endofstorage - _start;
}

三、构造函数

1、默认构造函数

这里不像前面string类一样,就算创建一个空的对象,也需要开辟一个空间存放 \0

一开始的时候,我们无需开辟空间;等到有数据输入的时候,再开辟空间

vector()
	:_start(nullptr),
	_end(nullptr),
	_endofstorage(nullptr)
{
}

2、输入开辟的元素个数,根据元素个数开辟空间

尽管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

3、通过迭代器初始化

前面说了,迭代器可以看作是 指针,迭代器初始化就是给定其他 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

(1) 扩容 reserve

注意reserve和resize的区别

  • reserve:仅改变容器容量 capacity,有效数据个数 size 不变
  • resize:同时改变容器容量 capacity 和 有效数据个数 size。capacity = size = 默认值(初始值)
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;
	}

}

(2) 插入 push_back

void push_back(const T& val)
{
	//判断是否需要扩容
	if (_end == _endofstorage)
	{
		reserve(_start == nullptr ? 4 : capacity() * 2);
	}

	*_end = val;            
	_end++;                //实际数据个数加 1
}

(3) 构造函数:迭代器初始化

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;
}

4、通过对象初始化(拷贝构造)

这里就和string 类似了,详情可以参考下面博客中的拷贝构造函数部分

string类的模拟实现(一)—— 构造函数(无参、拷贝等)_abs(ln(1+NaN))的博客-CSDN博客https://blog.csdn.net/challenglistic/article/details/123169009?spm=1001.2014.3001.5501

(1) swap函数

void swap(vector& v1, vector& v2)
{
	std::swap(v1._start, v2._start);
	std::swap(v1._end, v2._end);
	std::swap(v1._endofstorage , v2._endofstorage);
}

(2) 拷贝构造函数

vector(vector& v)
{
	vector tmp(v.begin(), v.end());
	swap(*this, tmp);
}

你可能感兴趣的:(C/C++,c++)