vector的底层实现!(万字长文详解!)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vector的底层实现!(万字长文详解!)相关的知识,希望对你有一定的参考价值。

vector的底层简单实现!

vector的成员变量

template<class T>
class vector

    typedef T* iterator;//迭代器
	typedef const T* const_iterator;
private:
	iterator _start;
	iterator _finish;
	iterator _endofstorage;
;

reserve

void reserve(size_t n)

	if (n > capacity())
	
		T* temp = new T[n];
		size_t OldSzie = size();
		if (_start != nullptr)//万一一开始是空,那么就没有必要拷贝数据了!
		
			for (size_t i = 0; i < OldSzie; i++)
			
				temp[i] = _start[i];
			
			delete[] _start;
		
		_start = temp;
		_finish = _start + OldSzie;
		_endofstorage = _start + n;
	

push_back

void push_back(const T& value)

	if (_finish == _endofstorage)
	
		size_t newcapaciy = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapaciy);
	
	*_finish = value;
	_finish++;


构造函数

vector()
	:_start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)


template<class InputIterator>
vector(InputIterator first, InputIterator last)
	: _start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)

	while (first != last)
	
		push_back(*first);
		first++;
	

构造函数的冲突

vector(size_t n, const T& val = T())
	: _start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)

	reserve(n);
	for (size_t i = 0; i < n; i++)
	
		push_back(val);
	

而这个构造函数

vector(size_t n, const T& val = T());

解决办法

  1. My_STL::vector<char> v((size_t)10, a);//进行强转!
    
  2. //写一个函数重载只要有一个更匹配的函数就不会去调用上面的模板函数了!
    //因为调用模板函数还需要实例化
    vector(int n, const T& val = T())
    	: _start(nullptr),
    	_finish(nullptr),
    	_endofstorage(nullptr)
    
    	reserve(n);
    	for (int i = 0; i < n; i++)
    	
    		push_back(val);
    	
    
    

所以最后的完成版就是

vector()
	:_start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)


template<class InputIterator>
vector(InputIterator first, InputIterator last)
	: _start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)

	while (first != last)
	
		push_back(*first);
		first++;
	


vector(size_t n, const T& val = T())
	: _start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)

	reserve(n);
	for (size_t i = 0; i < n; i++)
	
		push_back(val);
	

vector(int n, const T& val = T())
	: _start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)

	reserve(n);
	for (int i = 0; i < n; i++)
	
		push_back(val);
	

析构函数

~vector()

	delete[] _start;
	_start = _finish _endofstorage = nullptr;

size

size_t size()const

    return _finish - _start;

capacity

size_t capacity()const

	return _endofstorage - _start;

begin

iterator begin()const

	return _start;

end

iterator end()const

	return _finish;

empty

bool empty()const

	return _finish == _start;

pop_back

void pop_back()

	assert(!empty());
	--_finish;

[]重载

T& operator[](size_t pos)

	assert(pos < size());
	return _start[pos];

T& operator[](size_t pos)const

	assert(pos < size());
	return _start[pos];

resize

void resize(size_t n, T value = T())

	if (n > capacity())
	
		reserve(n);
	
	if (n > size())
	
		while (_finish < _start + n)
		
			*_finish = value;
			++_finish;
		
	
	if (n < size())
	
		_finish = _start + n;
	

insert——重点

但是即使是上面的写法也不能完全避免迭代器失效的问题!

因为我们只是避免了里面的迭代器失效!还有外面的迭代器失效我们无法避免!

int main()

	My_STL::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	My_STL::vector<int> ::iterator it = find(v1.begin(), v1.end(), 3);
	v1.insert(it, 30);
	cout << (*it) << endl;
	return 0;

因为我们当里面发生扩容的时候!外面的迭代器还是指向的是旧的空间!这就是一个越界访问!是一个野指针!

==为了安全考虑所以当我们使用it之后无论它是否真的失效了!我们一律都认为它是失效的!==

==为了安全如果要再次使用it最好进行更新!==

iterator insert(iterator pos, const T& val)

	assert(pos >= _start);
	assert(pos <= _finish);
	if (_finish == _endofstorage)
	
		size_t len = pos - _start;
		int NewCapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(NewCapacity);
		pos = _start + len;
		//这里一旦扩容!就会导致一个很严重的问题就是地址发生了改变!
	

	iterator end = _finish - 1;
	while (end >= pos)
	
		*(end + 1) = *end;
		--end;
	
	*(pos) = val;
	_finish++;
	return pos;

我们可以使用==iterator==作为返回值!==返回插入后值的位置!==

这样我们可以在使用it之后 使用it接收这个返回值!更新it

int main()

	My_STL::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	My_STL::vector<int> ::iterator it = find(v1.begin(), v1.end(), 3);
	it = v1.insert(it, 30);
	cout << (*it) << endl;
	return 0;


erase——重点

这样子写就可以在g++下面和vs下面的都是可以运行!就无关平台了!

clear

void clear()

	_finish - _start;

swap

void swap(vector<T>& v)

	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_endofstorage, v._endofstorage);

拷贝构造

写法一

写法二

vector(const vector<T>& v)
	: _start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)

	vector<T> tmp(v.begin(), v.end());
	swap(tmp);

赋值运算符重载

vector<T>& operator=(vector<T> v)

	swap(v);
	return *this;

使用memcpy实现reserve的缺陷——重要

总结

==这也是为什么我们在c++中使用new和delete的原因而不是使用malloc的free==

==因为new和delete会去自动的调用构造和析构函数而malloc和free却不会!和自定义类型其实不相符合!==

全部代码

#pragma once
#include <iostream>
#include<vector>
#include<assert.h>
using namespace std;
namespace My_STL

	template<class T>
	class vector
	
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		vector()
			:_start(nullptr),
			_finish(nullptr),
			_endofstorage(nullptr)
		

		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
			: _start(nullptr),
			_finish(nullptr),
			_endofstorage(nullptr)
		
			while (first != last)
			
				push_back(*first);
				first++;
			
		

		vector(size_t n, const T& val = T())
			: _start(nullptr),
			_finish(nullptr),
			_endofstorage(nullptr)
		
			reserve(n);
			for (size_t i = 0; i < n; i++)
			
				push_back(val);
			
		

		vector(int n, const T& val = T())
			: _start(nullptr),
			_finish(nullptr),
			_endofstorage(nullptr)
		
			reserve(n);
			for (size_t i = 0; i < n; i++)
			
				push_back(val);
			
		
		vector(const vector<T>& v)
			: _start(nullptr),
			_finish(nullptr),
			_endofstorage(nullptr)
		
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);
		
		~vector()
		
			delete[] _start;
			_start = _finish = _endofstorage = nullptr;
		

		vector<T>& operator=(vector<T> v)
		
			swap(v);
			return *this;
		


		size_t size()const
		
			return _finish - _start;
		
		size_t capacity()const
		
			return _endofstorage - _start;
		
		iterator begin()const
		
			return _start;
		
		iterator end()const
		
			return _finish;
		
		T& operator[](size_t pos)
		
			assert(pos < size());
			return _start[pos];
		
		T& operator[](size_t pos)const
		
			assert(pos < size());
			return _start[pos];
		
		void reserve(size_t n)
		
			if (n > capacity())
			
				T* temp = new T[n];
				size_t OldSzie = size();
				if (_start != nullptr)
				
					for (size_t i = 0; i < OldSzie; i++)
					
						temp[i] = _start[i];
					
					delete[] _start;
				
				_start = temp;
				_finish = _start + OldSzie;
				_endofstorage = _start + n;
			
		
		void resize(size_t n, T value = T())
		
			if (n > capacity())
			
				reserve(n);
			
			if (n > size())
			
				while (_finish < _start + n)
				
					*_finish = value;
					++_finish;
				
			
			if (n < size())
			
				_finish = _start + n;
			
		
		void push_back(const T& value)
		
			if (_finish == _endofstorage)
			
				size_t newcapaciy = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapaciy);
			
			*_finish = value;
			_finish++;

		
		bool empty()const
		
			return _finish == _start;
		
		void pop_back()
		
			assert(!empty());
			--_finish;
		
		void clear()
		
			_finish - _start;
		
		void swap(vector<T>& v)
		
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		
		iterator insert(iterator pos, const T& val)
		
			assert(pos >= _start);
			assert(pos < _finish);
			if (_finish == _endofstorage)
			
				size_t len = pos - _start;
				int NewCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(NewCapacity);
				pos = _start + len;
			

			iterator end = _finish - 1;
			while (end >= pos)
			
				*(end + 1) = *end;
				--end;
				
			*(pos) = val;
			 _finish++;

			 return pos;
		

		iterator erase(iterator pos)
		
			assert(pos >= _start);
			assert(pos < _finish);
			iterator begin = pos + 1;
			while (begin < _finish)
			
				*(begin-1) = *(begin);
				++begin;
			
			_finish--;
			return pos;
		

	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	;




以上是关于vector的底层实现!(万字长文详解!)的主要内容,如果未能解决你的问题,请参考以下文章

STL之list底层简单实现(七千字长文详解!)

万字长文详解Shardingsphere对XA分布式事务的支持

leetcode 28. 实现 strStr()----KMP算法,朴素模式匹配算法----超万字长文详解

万字长文详解HiveSQL执行计划

万字长文详解二叉树算法,再也不怕面试了!| 技术头条

万字长文详解HiveSQL执行计划