CD42.【C++ Dev】vector模拟实现(1)

目录

1.知识回顾

2.SGI STL的vector

3.模拟实现

框架

构造函数

capacity函数

size函数

begin函数和end函数

reserve函数

push_back函数

扩容分两种情况讨论

测试代码

1.T为内置类型

2.T为自定义类型

调试可以看出start、finish和end_of_storage使用迭代器是有好处的,能应对不同的模版!

析构函数


1.知识回顾

与vector1相关的知识点:
CC29.【C++ Cont】STL库:动态顺序表(vector容器)

CD41.补充vector细碎的知识点

2.SGI STL的vector

模拟实现vector前,先看看SGI STl中的vector的结构:

使用《STL源码剖析》提到的STL v3.0中的vector,先看框架:

可以看到有vector类,其外有operator==、operator<、operator=、insert_aux和insert函数

再看成员变量:肯定在vector类里面:

start、finish、end_of_storage的含义可以参见《STL源码剖析》的示意图:

类比之前CD37.【C++ Dev】string类的模拟实现(1)文章string的模拟实现,

class string
{
	//......
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

_str相当于这里的start,_size相当于这里的finish,_capacity相当于这里的end_of_storage

发现这3个成员变量的类型为iterator,而且iterator实际上是指针(因为vector是一段连续的空间,用指针利于访问)

typedef value_type* iterator;

再看构造函数:

vector() : start(0), finish(0), end_of_storage(0) {}

使用初始化成员列表,一开始vector为空,所以全初始化为0

当然也可以使用C++11的缺省值的写法:

namespace mystl
{
	template<class T>
	class vector
	{
	public:
		typedef T value_type;
		typedef value_type* iterator;
		typedef const value_type* const_iterator;    
        typedef size_t size_type;
		//各种成员函数
		iterator start = 0;
		iterator finish = 0;
		iterator end_of_storage = 0;
	};
}

其余函数同理分析

3.模拟实现

实现一个简化版本的vector

finish指向最后一个有效元素的下一个位置,end_of_storage指向存储空间的结尾

框架

保持和SGI STL一样的风格:

namespace mystl
{
	template<class T>
	class vector
	{
	public:
		typedef T value_type;
		typedef value_type* iterator;
		typedef const value_type* const_iterator;    
        typedef size_t size_type;
		//各种成员函数
		iterator start;
		iterator finish;
		iterator end_of_storage;
	};
}

构造函数

全部填0就行

vector() : start(0), finish(0), end_of_storage(0) {}

capacity函数

size_type capacity() const
{
	return end_of_storage - start;
}

size函数

参数保持一样的类型:

size_type size() const 
{
	return finish - start;
}

begin函数和end函数

参数保持一样的类型:

实现两个:

iterator begin()
{
	return start;
}

const_iterator begin() const
{
	return start;
}

实现两个: 

iterator end()
{
	return finish;
}

const_iterator end() const
{
	return finish;
}

reserve函数

参数保持一样的类型:

CD37.【C++ Dev】string类的模拟实现(1)文章的reserve实现思想类似,在reserve中必须检查n和capacity()的大小关系,别人调用reserve不一定会提前检查

void  reserve(size_type n)
{
	if (n > capacity())
	{
		T* tmp = new T[n];
		size_t len = size();//delete前先保存元素的个数!
		memmove(tmp,start , size()* sizeof(value_type));
		delete[] start;
		start = tmp;
		finish = start + len;
		end_of_storage = start + n;
	}
}

(开空间使用new,不使用空间配置器,简化操作) 

capacity()返回的是元素的个数,memove函数第三个参数是字节数,需要写成capacity()*sizeof(value_type)

(sizeof(value_type)是单个元素所占的空间大小,单位是字节)

如果start是有效的,肯定没问题,但如果是刚初始化的vector,从构造函数来看,刚刚初始化时立刻指向reserve,start为空指针,在执行memmove时也没有问题

再看为什么需要定义len:

扩容后,一般是异地扩容,原来的start和扩容后的start指向的地址肯定不同,为了定位扩容后的finish,为了让finish移到新位置,必须先算出原来有效元素的个数,使用len记录

注意:必须在delete前先保存元素的个数!

*注:这个reserve函数其实有错误,自定义类型的深拷贝会出问题,在之后的文章会改过来 

push_back函数

尾插的前提:空间要足够,否则需要扩容

扩容分两种情况讨论

一开始start和end_of_storage都为空时尾插会有问题,需要先开辟空间后尾插,除此之外,start不为空,可以按一般的二倍扩容进行

void push_back(const value_type& val)
{
	if (finish == nullptr)
		reserve(4);
	if (finish == end_of_storage)
			reserve(capacity() * 2);
	*finish = val;
	finish++;
}

测试代码

1.T为内置类型
#include "vector.h"
void test1()
{
	mystl::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	//往下二倍扩容
	v.push_back(1);
	for (auto a : v)
		std::cout << a << std::endl;
	return;
}

int main()
{
	test1();
	return 0;
}

运行结果:

 

2.T为自定义类型

例如使用std::string作为自己实现的vector的模版

void test2()
{
	mystl::vector<std::string> v_str;
	v_str.push_back("abc");
	v_str.push_back("de");
	v_str.push_back("f");
	v_str.push_back("ghijk");
	for (auto a : v_str)
		std::cout << a << std::endl;
	return;
}

运行结果:

注:当push_back的vector个数超过4个时会出问题,原因在reserve函数,这个后面文章会修复

调试可以看出start、finish和end_of_storage使用迭代器是有好处的,能应对不同的模版!

push_back其实是一个个的string对象,不单单是字符串

同理,其实如果插入的string对象大于4个,也会出深拷贝问题,后面的博客将修复这个问题

析构函数

这样写是有问题的:

~vector()
{
	delete[] start;
	start = finish = end_of_storage = nullptr;
}

如果start为空,delete会有问题,因此需要先判断

~vector()
{
	if (start)
	{
		delete[] start;
		start = finish = end_of_storage = nullptr;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值