C++中vector类的用法介绍,迭代器失效和底层实现

1.vector介绍

vector 是表示可变大小数组的序列容器。就像数组一样,vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对 vector 的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
2.vector接口函数的使用
2.1 默认成员函数
  vector();   无参构造函数
vector size_type n, const value_type& val = value_type() );
构造并且初始化n个val
vector (const vector& x);
拷贝构造
vector (InputIterator fifirst, InputIterator last);
使用迭代器初始化构造
vector& operator=(const vector& x);赋值重载
void vector_test1()
{
	//无参构造
	vector<int> v1;
	//构造并初始化4个5
	vector<int> v2(4, 5);
	//使用对象st1进行迭代器构造
	string st1("hello world");
	vector<char> v3(st1.begin(), st1.end());
	//使用v2拷贝构造
	vector<int> v4(v2);
	//赋值重载
	vector<int> v5(3, 6);
	vector<int> v6;
	v6 = v5;
}

打印结果

2.2 vector iterator 的使用

begin() 获取第一个数据位置的 iterator

end() 获取最后一个数据的下一个位置的 iterator

void vector_test2()
{
//iterator begin();//修饰的对象可读可写
//const_iterator begin() const;//只读修饰的对象
string s("you are great!!!");
vector<char> v1(s.begin(), s.end());
vector<char>::iterator it = v1.begin();
while (it != v1.end())
{
	cout << *it;
	it++;
}
cout << endl;
for (auto e : v1)
{
	cout << e;
}
cout << endl;
}

//运行结果
//you are great!!!
//you are great!!!

2.3 vector容量的接口函数

void vector_test3()
{
string s("you are great!!!");
vector<char> v1(s.begin(), s.end());
//size() 判断vector中数据多少
cout << "数据个数: " << v1.size();
cout << endl;
//capacity() 容量大小
cout << "容量大小: " << v1.capacity();
cout << endl;
//empty() 判空 1非空 0空
cout <<"判空:"<< v1.empty();
cout << endl;
//resize() 扩容加初始化
v1.resize(20, 'y');//增容到20,字符串后补y
cout <<"容量大小:"<<v1.capacity() << endl;
for (auto e : v1)
{
	cout << e;
}
cout << endl;
v1.resize(10);//容量不变,vector中数据变成10个
cout <<"容量大小:"<< v1.capacity() << endl;
for (auto e : v1)
{
	cout << e;
}
cout << endl;
//reserve() 增容
v1.reserve(30);
cout <<"容量大小:"<<v1.capacity();
}

运行结果如下:

 2.4 vector的增删查改

  push_back尾插
  pop_back尾删
  find
查找。(注意这个是算法模块实现,不是 vector 的成员接口)
  insert
position 之前插入 val
  erase
删除 position 位置的数据
  swap
交换两个 vector 的数据空间
  operator[ ]
像数组一样访问
void vector_test4()
{
vector<int> v1(2, 5);
//尾插三个数据
v1.push_back(2);
v1.push_back(3);
v1.push_back(6);
//尾删一个数据
v1.pop_back();
for (auto e : v1)
{
	cout << e <<" ";
}
cout << endl;
//运行结果:5 5 2 3
InputIterator find(InputIterator first, InputIterator last, const T& val);
找到你要查找的数并返回迭代器
auto pos = find(v1.begin(), v1.end(),3);
在pos位置前面插入val iterator insert (iterator position, const value_type& val);
v1.insert(pos, 9);
for (auto e : v1)
{
	cout << e <<" ";
}
cout << endl;
//运行结果:5 5 2 9 3
在pos位置前插入n个val
void insert(iterator position, size_type n, const value_type & val);
在pos位置前插入一段迭代器区间,表示插入一个vector对象的一部分
void insert(iterator position, InputIterator first, InputIterator last);
}
pos = find(v1.begin(), v1.end(), 3);
v1.erase(pos);
for (auto e : v1)
{
	cout << e<<" ";
}
cout << endl;
//运行结果:5 5 2 9
vector<int> v2(4, 7);
v1.swap(v2);
for (auto e : v1)
{
	cout << e<<" ";
}
cout << endl;
//运行结果:7 7 7 7
//operator[]
for(int i=0;i<v2.size();i++)
{
cout<<v2[i]<<" ";
}
//运行结果:5 5 2 9

3.迭代器失效

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了 封装 ,比如: vector 的迭代器就是原生态指针 T* 。因此 迭代器失效,实际就是迭代器层对应指针所指向的 空间被销毁了,而使用一块已经被释放的空间 ,造成的后果是程序崩溃 ( 如果继续使用已经失效的迭代器, 程序可能会崩溃 )
举俩个例子来加以说明:
一  思想:尾插1,2,3,4四个数据,找到为3数据的下标,然后插入一个数据30,没插入之前 vector对象v1的容量为4,插入之后需要扩容,v1的指针指向了新开辟的空间,之前指针指向的那块区域已经被释放,pos指针指向的是已经释放的空间,所以用pos指针访问和在pos指针前插入数据就是非法访问。
图如下:
代码如下:
void test_vector5()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
auto pos=find(v1.begin(), v1.end(), 3);
if (pos != v1.end())
{
	cout << "找到了";
}	
v1.insert(pos, 30);
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
cout << pos << endl;
v1.insert(pos, 40);
v1.insert(pos, 50);
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
}

二  思想:vector是一段连续的物理空间,删除一个数后,后面的空间会向前移动,这时候如果it++,就会跑到删除这个数地址的后俩位。

思维图:


代码如下:

void test_vector6()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
//删除所有偶数
yht::vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
	if (*it % 2 == 0)
	{
	v1.erase(it);
	}
	else
	it++;
}
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
}
//程序崩溃

4.string底层实现

#include <iostream>
using namespace std;
#include <assert.h>
#include <algorithm>
#include <string>

namespace yht
{
template<class T>
class vector	{
public:
	typedef T* iterator;
	typedef const T* const_iterator;
	vector()//构造
		:_start(nullptr)
		,_finish(nullptr)
		,_end_of_storage(nullptr)
	{}
	template <class InputIterator>
	vector(InputIterator first, InputIterator last)
		: _start(nullptr)
		, _finish(nullptr)
		, _end_of_storage(nullptr)
	{
		while (first != last)
		{
			push_back(*first);
			++first;
		}	
	}
	vector(size_t n, const T& val = T())
		: _start(nullptr)
		, _finish(nullptr)
		, _end_of_storage(nullptr)
	{
		for (size_t i = 0; i < n; i++)
		{
			push_back(val);
		}
	}
	//拷贝构造 传统写法
	/*vector(const vector<T>& v)
	{
		_start = new T[v.size()];
		for (size_t i = 0; i < v.size(); i++)
		{
			_start[i] = v._start[i];
		}
		_finish = _end_of_storage = _start + v.size();
		
	}*/
	/*vector(const vector<T>& v)
	{
		_start = new T[v.size()];
		_finish = _end_of_storage = _start;
		for (int i = 0; i < v.size(); i++)
		{
			push_back(v._start[i]);
		}
	}*/
	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(const vector<T>& v)
	{
		vector<T> tmp(v.begin(), v.end());
		swap(tmp);
	}
	//v1=v2;
	vector<T>& operator=(vector<T> v)
	{
		swap(v);
		return *this;
	}
	~vector()//析构
	{
		if (_start)
		{
			delete[] _start;
			_start = _finish = _end_of_storage=nullptr;
		}
	}
	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 _end_of_storage - _start;
	}
	void reserve(size_t n)//提前开空间
	{
		if (n > capacity())
		{
			size_t sz = size();
			T* tmp = new T[n];
			if (_start)
			{
				memcpy(tmp, _start, sizeof(T) * size());
				delete[] _start;
			}
			_start = tmp;
			_finish = _start + sz;
			_end_of_storage = _start + n;
		}
	}
	void push_back(const T& x)
	{
		if (_finish == _end_of_storage)
		{
			reserve(capacity() == 0 ? 4 : capacity() * 2);
		}
		*(_finish) = x;
	_finish++;
	}
	void pop_back()
	{
		assert(_finish > _start);
		--_finish;
	}
	T& operator[](size_t pos)
	{
		return _start[pos];
	}
	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;
		}
		T* end = _finish;
		while(end>pos)
		{
			*(end) = *(end - 1);
			end--;
		}
		*pos = x;
		_finish++;
		return pos;
		}
	iterator erase(iterator pos)
	{
		assert(pos < _finish);
		T* end = pos + 1;
		while (end<_finish)
		{
			*(end - 1) = *end;
			end++;
		}
		_finish--;
		return pos;
	}
	void resize(size_t n, const T& val = T())
	{
		if (n > capacity())
		{
			reserve(n);
		}
		if (n > size())
		{
			while (_finish < _start+n)
			{
				push_back(val);
			}
		}
		else
		{
			_finish = _start + n;
		}
	}
private:
	T* _start;
	T* _finish;
	T* _end_of_storage;
};
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

疯狂的小码农

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值