vector介绍及底层原理

目录

1.介绍

2.模拟实现

2.1.基本框架

2.2.简单函数实现

2.3.扩容函数实现

2.4插入删除函数实现 

2.5构造函数等 

2.6迭代器失效问题


1.介绍

1. vector 是表示可变大小数组的序列容器。
2. 就像数组一样, vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对                 vecto 的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而          且它的大小会被容器自动处理
函数有: vector介绍及底层原理_第1张图片

 vector介绍及底层原理_第2张图片

举例:

void test_vector1()
{
	vector v;
	v.push_back(7);
	v.push_back(3);
	v.push_back(5);
	v.push_back(9);
	v.push_back(2);
	for (auto& ch : v)
	{
		ch += 1;
		cout << ch << " ";
	}
	cout << endl;
	vector::iterator it = v.begin();
	while (it != v.end())
	{
		(*it) -= 1;
		cout << *it << " ";
		it++;
	}
	cout << endl;

	sort(v.begin(), v. end());
	for (auto ch : v)
	{
		cout << ch << " ";
	}
	cout << endl;
}

结果:

8 4 6 10 3
7 3 5 9 2
2 3 5 7 9

int main()
{
	vector v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);

	vector::iterator it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
		{
			it = v.insert(it, 20);//insert返回的是新插入元素的后一个元素的地址
			it++;
		}
		it++;
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

结果:
1 20 2 3 20 4 5 20 6

用法与string类似,可查看文档:vector - C++ Reference 进行学习。

2.模拟实现

2.1.基本框架

namespace LF
{
	template
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		vector()//无参构造函数
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{}


		//........其余函数的实现

	private:
		iterator _start;//T类型的指针,指向该内存空间起始位置
		iterator _finish;//指向有效数据的位置
		iterator _endofstoage;//指向该内存结束位置
	};
}

2.2.简单函数实现

        iterator begin()//返回起始空间的地址
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		size_t size() const//返回元素的个数
		{
			return _finish - _start;
		}

		size_t capacity() const//返回容量的大小
		{
			return _endofstoage - _start;
		}
        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 clear()
		{
			_finish = _start;
		}

2.3.扩容函数实现

       void reserve(size_t n)
		{
			size_t sz = size();
			if (n > capacity())
			{
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, size()*sizeof(T));

                     for (size_t i = 0; i < size(); ++i)
					{
						tmp[i] = _start[i];//若—_start[i]是vector类型,里面有指针,要完成深拷贝
					}
					delete[] _start;
				}
		
				_start = tmp;//_start所指向的空间改变了
			}

			_finish = _start + sz;//扩容后—_start改变了,—_finish应在新的_start后面
			_endofstoage = _start + n;
		}

		void resize(size_t n, T val = T())//T()会去调用它的默认构造函数,在C++中,内置类型也有默认构造函数
		{
			if (n > capacity())
			{
				reserve(n);
			}

			if (n > size())
			{
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}

2.4插入删除函数实现 

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

			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			if (_finish > _start)
			{
				--_finish;
			}
		}

       iterator insert(iterator pos , const T&)//此处pos接受的是值传递
		{
			assert(pos >= _start && pos <= _finish);
			size_t sz = pos - _start;
			if (_finish == _endofstoage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 4;
				reverse(newcapacity);
				pos = _start + sz;//扩容后,pos指向的内存空间也失效了,要重新赋值
			}
			// 2  4  6  7 
			iterator end = _finish - 1;
			while (end>=pos)
			{
			
				*(end + 1) = *end;
				end--;
			}
			*pos = x;
			++_finish;

			return pos;//返回的pos指针是指向新元素的
		}

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

2.5构造函数等 

        template 
		vector(InputIterator first, InputIterator last)
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(size_t n, const T& val = T())
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(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)
			, _endofstoage(nullptr)
		{
			reserve(n);
			for (int i = 0; i < n; ++i)
			{
				push_back(val);
			}
		}

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

	
		vector(const vector& v)
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{
			vector tmp(v.begin(), v.end());//构造一个临时对象,开辟新空间,内容与v相同
			swap(tmp);//将*this与tmp中的三个指针交换。
		}


		vector& operator=(vector v)//值传递
		{
			swap(v);
			return *this;
		}

2.6迭代器失效问题

        iterator insert(iterator pos , const T&)//此处pos接受的是值传递
		{
			assert(pos >= _start && pos <= _finish);
			size_t sz = pos - _start;
			if (_finish == _endofstoage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 4;
				reverse(newcapacity);
				pos = _start + sz;//扩容后,pos指向的内存空间也失效了,要重新赋值
			}
			// 2  4  6  7 
			iterator end = _finish - 1;
			while (end>=pos)
			{
			
				*(end + 1) = *end;
				end--;
			}
			*pos = x;
			++_finish;

			return pos;//返回的pos是指向新元素的
		}

库里面的实现与上面原理类似,每次插入新元素后,返回的是新元素的地址。

倘若在没有接受该函数的返回值的情况下:

1.若未发生扩容,此时的pos指针指向新插入的数据。

2.若发生扩容,由于该函数中pos是值传递,即使在函数内部改变了pos,在未接受返回值的情况下,该pos所指向的内存空间已经失效了。

在vs2022下演示:

int main()
{
	vector v;
	v.reserve(10);
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(5);
	v.push_back(6);
	auto pos = find(v.begin(), v.end(), 5);
	if (pos!=v.end())
	{
		cout << "capacity:"<

vector介绍及底层原理_第3张图片

vector介绍及底层原理_第4张图片

在未扩容的情况下,pos所指向的空间不变,但数据改变了,在vs2022平台上不能进行访问(vs2014可以访问)

vector介绍及底层原理_第5张图片

vector介绍及底层原理_第6张图片

 在扩容的情况下,pos所指向的空间已失效。vextor已重新开辟了新的空间。

        iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);
			iterator it = pos + 1;
			while (it != _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;
			return pos;//返回的pos指向的数据是被删除元素的下一个元素
		}

因为erase函数删除数据时,不会减小容量,不会存在野指针问题,但pos指向的数据意义变了(与insert中第二种情况一样)。vs2022下不可访问,可认为失效了。

vector介绍及底层原理_第7张图片

 不同平台下检查机制不一样,可能有不同的结果,

总结:在使用insert,erase函数时,最好要接受它的返回值。

你可能感兴趣的:(C++入门学习,c++)