C++的vector

文章目录

  • 迭代器失效问题
  • 构造函数
  • 赋值运算符
  • begin() + end()
  • size() + capacity() + empty()
  • reserve()
  • operator[ ]
  • insert()
  • erase()
  • resize()

迭代器失效问题

迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间
1.扩容导致迭代器失效问题
在对容器进行insert、resize、reserve、assign、push_back等操作时会导致_capacity发生变化,在容量发生变化时,可能会出现异地扩容,这就会导致原来的迭代器指向已经被释放的空间,从而导致程序崩溃。
2.指定位置元素的删除操作----erase

#include 
#include 
using namespace std;

int main()
{
	int ar[] = { 1,2,3,4,0,5,6,7,8,9 };
	int n = sizeof(ar) / sizeof(int);
	vector<int> v(ar, ar + n);
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		if (*it != 0)
			cout << *it;
		else
			v.erase(it);
		it++;
	}
	return 0;
}

以上述程序为例,如果是在VS中只要是在删除操作后,迭代器就会失效,如果不给迭代器重新赋值,直接再次使用迭代器就会强制报错,而在Linux中不一定会报错,因为可能会误打误撞的让程序可以运行,结果也会正确
上述程序理论上可以正常运行,但是在VS中规定只要是在erase之后再次直接使用迭代器就会强制报错

构造函数

C++的vector_第1张图片
无参构造

vector()
	:_start(nullptr)
	,_finish(nullptr)
	,_end_of_storage(nullptr)
{

}

拷贝构造

//拷贝构造
//因为浅拷贝会导致析构时被析构两次,所以我们要写一个深拷贝
vector(const vector<T>& v)
	:_start(nullptr)
	,_finish(nullptr)
	,_end_of_storage(nullptr)
{
	_start = new T[v.capacity()];
	memcpy(_start, v._start, sizeof(T) * v.size());
	_finish = _start + v.size();
	_end_of_storage = _start + v.capacity();
}

使用迭代器进行初始化构造

template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

赋值运算符

在这里插入图片描述

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& operator=(vector& v)
vector<T>& operator=(vector<T> v)//参数v要是拷贝的,传引用的话就是原对象,赋值后这里会导致原对象被改变
{
	swap(v);
	return *this;
}

begin() + end()

在这里插入图片描述
在这里插入图片描述

iterator begin()
{
	return _start;
}

iterator end()
{
	return _finish;
}

const_iterator begin() const
{
	return _start;
}

const_iterator end() const
{
	return _finish;
}

size() + capacity() + empty()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

bool empty() const
{
	return _end_of_storage == _start;
}

reserve()

在这里插入图片描述

void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t sz = size();
		T* tmp = new T[n];
		if (_start)//如果空间中此时有数据
		{
			memcpy(tmp, _start, sizeof(T) * sz);
			delete[] _start;
		}
		_start = tmp;
		//_finish = _start + size();//size的计算会出错,因为此时的_start的指向已经发生改变,_finsh还是指向原来的位置
		_finish = _start + sz;
		_end_of_storage = _start + n;
	}
}

operator[ ]

在这里插入图片描述

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

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

insert()

C++的vector_第2张图片

//insert以后迭代器可能会失效(扩容)
//insert以后就不要使用这个迭代器了,因为他可能失效了
void insert(iterator pos, const T& x)//位置传指针就会避免在0位置插入导致的整型提升问题,因为地址不会小于0
{
	assert(pos >= _start && pos <= _finish);
	if (_finish == _end_of_storage)
	{
		//注意迭代器失效问题
		//因为一旦扩容,就会导致pos指向的位置还是原来的位置,而扩容后_start指向了新空间
		size_t len = pos - begin();//1保存pos相对位置
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
		pos = _start + len;//2更新pos指向
	}
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		end--;
	}
	*pos = x;
	_finish++;
}

erase()

在这里插入图片描述

//vs下进行强制检查只要用过insert或erase后再次访问就会出错,但是gcc下不强制检查,有可能会正好正确,但是这是偶然性的
//erase以后迭代器失效了,不能访问
iterator erase(iterator pos)
{
	assert(pos >= begin() && pos < end());
	
	/*while (pos < end())
	{
		*pos = *(pos + 1);
		pos++;
	}*/
	iterator it = pos;
	while (it != _finish)
	{
		*(it) = *(it + 1);
		it++;
	}
	_finish--;
	//返回删除位置的下一个位置,其实在删除后就是pos位置
	return pos;
}

resize()

在这里插入图片描述

//C++模板对默认构造进行了升级,即使是内置类型也会有相应的默认构造
//所以这里是可以使用匿名对象的,即使T是内置类型
void resize(size_t n, const T& val = T())
{
	if (n < size())
	{
		_finish = _start + n;
	}
	else
	{
		reserve(n);
		while (_finish != (_start + n))
		{
			
			/**_finish = val;
			_finish++;*/
			*(_finish++) = val;
		}
	}
}

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