Vector简单实现

一、vector的介绍和使用

1.1 vector的介绍

vector是表示可变大小数组的序列容器。
就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。 

在我个人理解中,我把它看成一个数组,只不过可以存你所需要的各种内置类型或自定义类型

迭代器相关

Vector简单实现_第1张图片

容量相关

Vector简单实现_第2张图片

shrink_to_fit是缩容

访问元素

Vector简单实现_第3张图片

修改元素

Vector简单实现_第4张图片

1.2vector的使用

和之前介绍的string类似,或者说类模板的使用基本类似

void test_vector1()
{
	vector v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	// vector
	// string
	// 

	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	vector::iterator it1 = v.begin();
	while (it1 != v.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

二、vector的模拟实现以及刨析

框架

namespace xxx
{
	template
	class vector
	{
    private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storage; 

	};
}

迭代器

typedef T* iterator;
typedef const T* const_iterator;


iterator begin()
{
		return _start;
}
iterator end()
{
    return _finish;
}
const_iterator begin() const
{
	return _start;
}
const_iterator end() const
{
	return _finish;
}

构造、析构和重载=

// construct and destroy
vector()
	:_start(nullptr)
	, _finish(nullptr)
	, _end_of_storage(nullptr)
{}

vector(int n, const T& v = T())
	:_start(nullptr)
	, _finish(nullptr)
	, _end_of_storage(nullptr)
{
	reserve(v.capacity());
	for (auto e : v)
	{
		push_back(e);
	}
}

vector(const vector& v)
{
	_start = new T[v.capacity()];
	memcpy(_start, v._start, sizeof(T) * v.size());
	_finish = _start + v.size();
	_end_of_storage = _start + v.capacity();
}

//迭代器区间构造
template 
vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}




vector& operator= (vector v)
{
	swap(v);
	return *this;
}

~vector()
{
	if (_start)
	{
		delete[] _start;
		_start = _finish = _end_of_storage = nullptr;
	}
}

 有效个数、扩容和resize

size_t size() const
{
	return _finish - _start;
}

size_t capacity() const
{
	return _end_of_storage - _start;
}

扩容 

注意:这个reserve有问题稍后会提到

void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t old_size = size();
		T* tmp = new T[n];
		if (_start)
		{
			memcpy(tmp, _start, old_size * sizeof(T));
			delete[] _start;
		}
		_start = tmp;
		_finish = _start + old_size;
		_end_of_storage = _start + n;
	}
}

 

void resize(size_t n, const T& value = T())
{
	if (n > size())
	{
		reserve(n)
		while (_finish < _start + n)
		{
			*_finish = value;
			++_finish;
		}
	}
	else
	{
		_finish = _start + n;
	}
}

元素访问

注意访问位置不得超过有效数据范围

T& operator[](size_t pos)
{
	assert(pos < size());
	return _start[pos];
}

const T& operator[](size_t pos)const
{
	assert(pos < size());
	return _start[pos];
}

修改元素

尾插和尾删

void push_back(const T& x)
{
	if (_finish == _end_of_storage)
	{
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
	}
	*_finish = x;
	++_finish;
}

void pop_back()
{
	assert(size() > 0);
	--_finish;
}

swap交换


void swap(vector& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_end_of_storage, v._end_of_storage);
}

在某位置插入、删除

 注意:这里涉及到迭代器失效以及深浅拷贝的问题


void insert(iterator pos, const T& x)
{
		assert(pos >= _start);
		assert(pos <= _finish);
		if (_finish == _end_of_storage)
		{
			//异地扩容_start会指向别的空间,pos的位置要记好
			size_t len = pos - _start;
			size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
			reserve(newcapacity);
			pos = _start + len;
		}
		memmove(pos + 1, pos, sizeof(T) * (_finish - pos));
		*pos = x;
		_finish++;
}

void erase(iterator pos)
{
	assert(pos >= _start);
	assert(pos <= _finish);
    iterator it = pos + 1;
	while(it < _finish)
    {
        *(it-1) = *it;
        ++it;
    }

	_finish--;
}

三、问题刨析

迭代器的主要作用就是让算法不用关心底层数据结构,底层可以理解为封装了一个指针

迭代器失效就是底层指针指向的空间已经被释放(会导致程序崩溃)

引起底层空间改变(例:扩容)的操作都有可能导致迭代器失效

3.1迭代器失效

Vector简单实现_第5张图片

Vector简单实现_第6张图片pos = _start+len;记录距离,并没有彻底的解决问题

外部的insert可能失效

v.insert(it,20);

 防不了这个,pos是it给的,内部的pos改变影响不了it,迭代器还是失效了

第二种失效

删除所有的偶数

void test_vector()
{
	vector v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(4);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);
	//v.push_back(7);

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	vector::iterator it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
		{
			v.erase(it);
		}
	
		++it;
	}

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

Vector简单实现_第7张图片

 

vector::iterator it = v.begin();
while (it != v.end())
{
	if (*it % 2 == 0)
	{
		it = v.erase(it);
	}
	else
	{
		++it;
	}
}

 

Vector简单实现_第8张图片

erase删除pos位置元素后,pos位置之后的元素会往前移动,没有导致底层空间的改变,理论上讲迭代器不会失效,但是如果pos位置刚好是最后一个元素,删完之后pos刚好是end的位置,而end的位置是没有有效元素的,那么pos就失效了。

迭代器失效后,代码并不一定会崩溃,如果it不在begin和end范围内,肯定会崩溃。

结论:insert和erase形参pos都可能会失效

原则是insert和erase过的迭代器不要使用

iterator erase(iterator pos)
{
	assert(pos >= _start);
	assert(pos < _finish);

	iterator it = pos + 1;
	while (it < _finish)
	{
		*(it - 1) = *it;
		++it;
	}
	_finish--;

	return pos;
}

3.2深浅拷贝问题

reserve中我们使用memcpy这个是浅拷贝

当vector存的是内置类型是这里没什么问题

但是如果是string等自定义类型就要出问题了

比如说

vector vstr;

那就会这样 

Vector简单实现_第9张图片 tmp中拷的_str还是指向原string的空间

reserve完会调用(string的)析构,string就会释放就空间,然而下面tmp的_str害指向那块空间呢

寄!

void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t old = size();
		T* tmp = new T[n];
		if (_start)
		{
			//memcpy(tmp, _start, old * sizeof(T));浅拷贝
			for (size_t i = 0; i < old; i++)
			{
				tmp[i] = _start[i];
			}

			delete[] _start;
		}

		_start = tmp;
		_finish = _start + old;
		_endofstorage = _start + n;
	}
}

insert插入

insert也用了memmove如果还是string那么也是浅拷贝,要改成深拷贝

iterator insert(iterator pos, const T& x)
{
	assert(pos >= _start && pos <= _finish);
	if (_finish == _endofstorage)
	{
		size_t len = pos - _start;
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos = _start + len;//迭代器失效
	}

	//memmove(pos + 1, pos, sizeof(T) * (_finish - pos));  浅拷贝
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;

	return pos;
}

 四、全部代码

#pragma once
#include

namespace xxx
{
	template
	class vector
	{
	public:
		// Vector的迭代器是一个原生指针
		typedef T* iterator;
		typedef const T* const_iterator;



		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}


		// construct and destroy
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

		vector(int n, const T& v = T())
		{
			resize(n,v);
		}

		vector(const vector& v)
		{
			reserve(v.capacity());
			for (const auto& e : v)
			{
				push_back(e);
			}
		}

		//迭代器区间构造
		template 
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}




		vector& operator= (vector v)
		{
			swap(v);
			return *this;
		}

		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _end_of_storage = nullptr;
			}
		}


		// capacity

		size_t size() const
		{
			return _finish - _start;
		}

		size_t capacity() const
		{
			return _end_of_storage - _start;
		}



		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, old * sizeof(T));   浅拷贝
					for (size_t i = 0; i < old; i++)
					{
						tmp[i] = _start[i];
					}

					delete[] _start;
				}

				_start = tmp;
				_finish = _start + old;
				_end_of_storage = _start + n;
			}
		}







		void resize(size_t n, const T& value = T())
		{
			if (n > size())
			{
				reserve(n);
				while(_finish < _start + n)
				{
					*_finish = value;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}

		///access///

		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}

		const T& operator[](size_t pos)const
		{
			assert(pos < size());
			return _start[pos];
		}



		///modify/

		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			assert(size() > 0);
			--_finish;
		}

		void swap(vector& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}


		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);

			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}

			//memmove(pos + 1, pos, sizeof(T) * (_finish - pos));
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;

			++_finish;

			return pos;
		}






		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			_finish--;

			return pos;
		}

	private:

		iterator _start;

		iterator _finish;

		iterator _end_of_storage; 

	};

}

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