C++ 7vector:动态数组的终极指南

vector的介绍

C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。

vector 是基于数组的数据结构,但它可以自动管理内存,这意味着你不需要手动分配和释放内存。

与 C++ 数组相比,vector 具有更多的灵活性和功能,使其成为 C++ 中常用的数据结构之一。

vector 是 C++ 标准模板库(STL)的一部分,提供了灵活的接口和高效的操作。

vector与数组相比,可以灵活变化空间大小,与灵活存储不同数据类型的值

相关文档推荐https://cplusplus.com/reference/vector/vector/

vector的使用

vector的定义

(constructor)构造函数声明 接口说明
vector()(重点) 无参构造
vector ( size_type n, const value_type& val = value_type()) 构造并初始化 n 个 val
vector (const vector& x); (重点) 拷贝构造
vector (InputIterator fifirst, InputIterator last); 使用迭代器进行初始化构 造
cpp 复制代码
vector<int>v1;//一个类型为int空的vector
vector<int>v2(6, 1);//{1,1,1,1,1,1,}
vector<int>v3 = v2;//上同
vector<int>v5{ 1,1,1,1,1,1, };//上同
vector<int>v4(++v3.begin(), --v3.end());//{1,1,1,1}

vector iterator****的使用

|-----------------------------------------------------------------------------|------------------------------------------------------------------------------|
| iterator的使用 | 接口说明 |
| begin + end (重点) | 获取第一个数据位置的 iterator/const_iterator , 获取最后一个数据的下 一个位置的iterator/const_iterator |
| rbegin + rend | 获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置 的reverse_iterator |

cpp 复制代码
vector<int>::iterator it = v3.begin();
while (it != v3.end())
{
	cout << *it;
	it++;
}

vector****空间增长问题

|--------------------------------------------------------------------------------|----------------------|
| 容量空间 | 接口说明 |
| size | 获取数据个数 |
| capacity | 获取容量大小 |
| empty | 判断是否为空 |
| resize | 改变 vector 的 size |
| reserve | 改变 vector 的 capacity |

cpp 复制代码
vector<int> v1(5, 2);
v1.reserve(3);//capacity仍为5
cout << v1.capacity() << endl;
v1.reserve(20);//空间变为20
cout << v1.capacity() << endl;

vector<int> v1(5, 2);
v1.reserve(10);//空间变为10
cout << v1.capacity() << endl;
v1.resize(4);//size变为4,删除大于3下标的数据
cout << v1.capacity() << endl;
v1.resize(49, 4);//size变为48,且3之后的下标数据用4填充,capacity也会自动扩容
cout << v1.capacity() << endl;

v1.size();//
v1,empty();

由于历史原因,string的reserve与vector的reserve有区别


若当前capacity小于n,则分配新内存(至少能容纳n个元素),并将原有元素复制 / 移动到新内存,旧内存释放。若capacity已≥n,则什么也不做(不会缩减容量)。

而string则在不同的编译器,缩容行为不同

迭代器失效问题

导致操作

扩容

cpp 复制代码
vector<int> v1{1,2,3,4};
v1.insert(v1.begin() + 2, 40);
//如果此处空间不够,进行扩容,那么原来v1,=,beign()指向的空间就被释放了,
解决办法:
使用相对位置更新

删除

假设此时it指向2,为偶数,删去,3挪到了2的位置,it再指向原来3的位置,如果此时为4,偶数就少删了

cpp 复制代码
vector<int> v1{1,2,3,45,6,7};
auto it = v1.begin();
while (it != v1.end())
{
	if (*it % 2 == 0)
		v1.erase(it);
		it++;
}

解决

cpp 复制代码
auto it = v1.begin();
while (it != v1.end())
{
	if (*it % 2 == 0)
		it = v1.erase(it);//更新it
	else
		it++;
}

vector的模拟实现

可能遇到的坑

深拷贝

此处不用memcpy进行拷贝的原因是,memcpy是一个一个字节的拷贝,如果拷贝对象为内存管理对象(如:string),就会进行浅拷贝,析构两次,错误

cpp 复制代码
void reserve(const size_t& n)
{
	size_t old_size = size();
	T* temp = new T[n];
	//std::memcpy(temp, _start, sizeof(T) * size());  
	for (int i = 0; i < old_size; i++)
		_str[i] = temp[i];
	delete[]_start;
	_start = temp;

	//_finish = _start + size();//不可,因为此处在size函数中,statr是已扩容的,而finish则是未扩容的
	//使用oldsize
	_finish = _start + old_size;
	_end_of_storage = temp + n;
}

解决迭代器失效问题

完整实现

cpp 复制代码
#pragma once
#include <assert.h>

namespace Milestone
{
	template <class T>//类模板的声明与定义不能分开写

	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin()
		{
			return _start;
		}
		const iterator begin()const
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const iterator end()const  //第一个const修饰返回值不可被修改,第二个const修饰this指针
		{
			return _finish;
		}
		void reserve(const size_t& n)
		{
			size_t old_size = size();
			T* temp = new T[n];
			//std::memcpy(temp, _start, sizeof(T) * size());  
			for (int i = 0; i < old_size; i++)
				_str[i] = temp[i];
			delete[]_start;
			_start = temp;

			//_finish = _start + size();//不可,因为此处在size函数中,statr是已扩容的,而finish则是未扩容的
			//使用oldsize
			_finish = _start + old_size;
			_end_of_storage = temp + n;
		}
		size_t size()const//修饰this指针
		{
			return _finish - _start;
		}
		size_t capacity()const
		{
			return _end_of_storage - _start;
		}
		size_t operator[](const int& n)
		{
			return *(_start + n);
		}
		const size_t operator[](const int& n)const
		{
			return *(_start + n);
		}
		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				reserve(capacity() == 0 ? 4 : 2 * sizeof(capacity()));
			}
			*_finish = x;//是成员函数,有this指针,访问_finish
			_finish++;
		}
		bool empty()
		{
			return _start == _finish;
		}
		void pop_back()
		{
			assert(empty());
			--_finish;
		}
		template<class T>
		void print_vector(const vector<T>& v)//打印vector,不改变,用const,再定义一个函数模板,是为了方便多种类型的打印
		{
			for (auto& e : v)
				std::cout << e << " ";
			std::cout << std::endl;
			//不能从没有实例化的类模板里面取东西,无法确定是类型还是静态成员变量
			//class与typename的区别 
			//加typename确定了是类型
			//或者使用auto,这个类型由后面的v.begin()推导
			//如果是静态成员变量不用加关键字
					//vector<T>::const_iterator it = v.begin();
			typename vector<T>::const_iterator it = v.begin();
			//auto vector<T>::const_iterator it = v.begin();
			/*while (it != v.end())
			{
				std::cout << *it << " ";
				it++;
			}
			std::cout << std::endl;
			for (int i = 0; i < size(); i++)
			{
				std::cout << v[i] << " ";
			}
			std::cout << std::endl;*/
		}
		//void insert(iterator pos,const T&x)//一:在某位置前插入,
		iterator insert(iterator pos, const T& x)//一:在某位置前插入,
			//为了下面能再对pos修改,返回更新后的pos
		{
			//迭代器失效:1 类似野指针
			//有可能空间不足,出现扩容
			if (_finish == _end_of_storage)
			{
				//使用相对位置更新pos
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * sizeof(capacity()));
				//但此时pos原来指向的空间被释放了,pos就相当于野指针了
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
			return pos;
		}

		iterator find(iterator left, iterator right, int x)

		{
			while (left != right)
			{
				if (*left == x)
					return left;
				++left;
			}
			return left;
		}
		iterator erase(iterator it)
		{
			assert(it >= _start);
			assert(it < _finish);
			iterator end = it;
			while (end < _finish - 1)
			{
				*end = *(end + 1);
				end++;
			}
			--_finish;
			return it;
		}
		void resize(const size_t n, T val = T())
		{
			//三种情况,size<_size  _size<size<capacity  size>capacity,后两种归为一种
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					_finish++;
				}
			}
		}
		~vector()
		{
			delete[]_start;
			_start = _finish = _end_of_storage = nullptr;
		}
		vector()//下面自己定义了拷贝构造,系统就不会走默认构造了,要自己定义
		{ }
		vector(const vector<T>& v)//拷贝构造
		{
			reserve(v.size());//提前开好空间,避免频繁扩容
			for (auto& e:v)
			{
				push_back(e);
			}
		}
		void clear()
		{
			_finish = _start;
		}
		//深拷贝  传统写法
		//vector<T>& operator=( const vector<T>& v)
		//{
		//	if (this != &v)//?
		//	{
		//		clear();//清除this指针里面的元素
		//
		//		reserve(v.size());
		//			for(auto& e : v)
		//			{
		//				push_back(e);
		//			}
		//	}
		//		return *this;
		// }
		//现代写法
		/*void swap(vector<T>& v)
		{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_end_of_storage, v._end_of_storage);
		}
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}*/
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while(first != last)//此处也可以用小于,但只适用于vector,他们在同一块空间,可以比较,但list这些就不行,所以使用!
			{
				push_back(*first);
				++first;
			}
			//构造函数和类名称一样
		}
		vector(size_t n, const T &val= T())
		{
			for (int i = 0; i < n; i++)
			{
				push_back(val);
			}
			
		}
		vector(int n, const T &val= T())
		{
			for (int i = 0; i < n; i++)
			{
				push_back(val);
			}
			
		}
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};
	void tv1()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		v1.print_vector(v1);//不为const,再定义一个const类型
	}
	void tv2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		//v1.push_back(5);
		v1.print_vector(v1);
		//v1.insert(v1.begin() + 2, 40);//要求左闭右开
		//v1.print_vector(v1);
		//在某个值前插入数据
		int x;
		std::cin >> x;
		 auto p = v1.find(v1.begin(), v1.end(), x);//左闭右开
		if (p != v1.end())//防止数据不存在
		{
			//v1.insert(p, 40);
			v1.print_vector(v1);
			//(*p) *= 10;
			//此处迭代器失效(建议不要访问),因为形参无法改变实参,形参使用引用,也类型不匹配,pos指向位置改变
			//要访问的话,更新pos
			p = v1.insert(p, 40);
			*p *= 10;
			v1.print_vector(v1);
		}

	}
	void tv3()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(4);
		v1.push_back(5);
		v1.print_vector(v1);//不为const,再定义一个const类型
		//删除所以偶数
		auto it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
				it = v1.erase(it);//更新it
			else
				it++;
		}
		v1.print_vector(v1);//不为const,再定义一个const类型
		v1.resize(5, 1);
		v1.print_vector(v1);//不为const,再定义一个const类型

	}
	void tv4()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		v1.print_vector(v1);//不为const,再定义一个const类型
		vector<int>v2 = v1;
		v2.print_vector(v2);//不为const,再定义一个const类型
		vector<int>v3;
		v3 = v1;
		v3.print_vector(v3);
	}
	void tv5()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		v1.print_vector(v1);//不为const,再定义一个const类型
		//迭代器构造
		vector<int> v2(v1.begin(), v1.begin() + 4);
		v2.print_vector(v2);//不为const,再定义一个const类型
		//n 个k
		vector<int>v3(5, 1);//此处5 c++默认`是int类型
		v3.print_vector(v3);//不为const,再定义一个const类型
		vector<int>v4(5);//此处5 c++默认`是int类型
		v4.print_vector(v4);//不为const,再定义一个const类型

	}
}
相关推荐
ss2732 小时前
高并发读场景:写时复制容器(Copy-On-Write)
java·开发语言·rpc
czhc11400756632 小时前
c# 1213
开发语言·数据库·c#
mit6.8242 小时前
get+二分|数位dp
算法
sin_hielo2 小时前
leetcode 2147
数据结构·算法·leetcode
萌>__<新2 小时前
力扣打卡每日一题——缺失的第一个正数
数据结构·算法·leetcode
DuHz2 小时前
车对车对向交汇场景的毫米波路径损耗建模论文精读
论文阅读·算法·汽车·信息与通信·信号处理
一人の梅雨2 小时前
淘宝商品视频接口深度解析:从视频加密解密到多端视频流重构
java·开发语言·python
是喵斯特ya2 小时前
java反序列化漏洞解析+URLDNS利用链分析
java·安全
她说..2 小时前
MySQL数据处理(增删改)
java·开发语言·数据库·mysql·java-ee