【C++】vector

本文介绍了C++标准库中的vector容器,包括其作为动态数组的特点,常用接口如resize和reserve的功能和区别,以及如何通过迭代器进行元素操作。还详细解析了vector的模拟实现,涵盖构造函数、拷贝构造、赋值运算符和迭代器管理等关键部分,强调了内存管理和效率优化的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vector简介

vector是表示可变大小数组的序列容器,数组中每个元素必须是同一种类型,并且有一个索引值,通常把vector称为容器。

vector常用接口总览

vector是一个类模板,可保存不同数据类型。

vector
保存string的vector: vector name;
保存int的vector:vector name;

我们在使用vector的时候必须在<>内说明vector内对象的类型

对象定义和初始化

在这里插入图片描述

如果只规定了容器元素的个数,没有指定初始化值,标准库会自动提供一个元素初始值。
如果该元素的类型为内置类型,则默认初始化值为0;若为类类型,标准库会用默认构造函数创建初始化。

迭代器相关

在这里插入图片描述

容量相关

在这里插入图片描述

vector中size和capacity的区别:
size指的是容器内元素的个数,capacity指的是容器内存空间的大小,一般来说capacity要比size大,确保元素个数增加时不需要重新分配内存。

resize 和 reserve

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

  1. capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。
  2. reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  3. resize在开空间的同时还会进行初始化,影响size。
  4. 如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够,用reserve,就可以避免边插入边扩容导致效率低下的问题了

增删查改

在这里插入图片描述

在这里插入图片描述

迭代器相关

vector<int>::iterator iter;

定义了一个迭代器iter,它的数据类型是由vector定义的iterator类型

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

vector模拟实现过程

各类接口总览

namespace han
{
    //模拟实现vector
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        //默认成员函数
        vector();                                       //构造函数
        vector(size_t n, const T& val);                 //构造函数
        template<class InputIterator>                      
        vector(InputIterator first, InputIterator last); //构造函数
        vector(const vector<T>& v);                  //拷贝构造函数
        vector<T>& operator=(const vector<T>& v); //赋值运算符重载
        ~vector();                                      //析构函数

        //迭代器相关函数
        iterator begin();
        iterator end();
        const_iterator begin()const;
        const_iterator end()const;

        //容量和大小相关函数
        size_t size()const;
        size_t capacity()const;
        void reserve(size_t n);
        void resize(size_t n, const T& val = T());
        bool empty()const;

        //修改容器内容相关函数
        void push_back(const T& x);
        void pop_back();
        void insert(iterator pos, const T& x);
        iterator erase(iterator pos);
        void swap(vector<T>& v);

        //访问容器相关函数
        T& operator[](size_t i);
        const T& operator[](size_t i)const;

    private:
        iterator _start;        //指向容器的头
        iterator _finish;       //指向有效数据的尾
        iterator _endofstorage; //指向容器的尾
    };
}


成员变量示意

在这里插入图片描述

迭代器相关

//迭代器相关函数
    
    typedef T* iterator;
	typedef const T* const_iterator;
	
    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 _endofstorage - _start;
	}

reserve函数

	void reserve(size_t n)
	{
		//reserve只扩容不缩容
		if(n>capacity())
		{
			size_t sz=size(); //记录扩容前容器内元素个数
			T* tmp=new T[n];
			if(_start)  //第一次扩容,_start为空,需判断
			{
			
				for(int i=0;i<sz;i++) //不能使用memcpy浅拷贝
				{
					tmp[i]=_start[i];
				}
				delete[] _start;
			}
			_start=tmp;
			_finish=_start+sz;
			_endofstorage=_start+n;
		}
	}

resize函数

void resize(size_t n,T val=T())
{
	if(n>capacity())
	[
		reserve(n);
	}
	//填数据
	if(n>size())
	{
		while(_finish<_start+n)
		{
			*_finish=val;
			_finish++;
		}
	}
	else //删除数据
	{
		_finish=_start+n;
	}

}

内容修改

push_back函数

void push_back(const T& x)
{
	if(_finish == _endofstorage) //判断是否需要扩容
	{
		reserve(capacity()==0?4:2*capacity());
	}
	*_finish=x;
	_finish++;
}

pop_back函数

void pop_back()
{
	assert(!empty());
	--_finish;
}

insert函数

使用insert函数插入元素时,需要考虑迭代器失效问题,当插入前容器需要扩容时,根据扩容原理,容器的空间地址发生变化,pos的值可能会发生变化,需要根据pos和_start的相对位置更新pos的值,再插入元素。
在这里插入图片描述

//pos位置插入val
iterator insert(iterator pos, const T& val)
{
	assert(pos >= _start);
	assert(pos < _finish);
	if(_finish==_endofstorage)
	{
		size_t len=_pos-_start;
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos=_start+len; //更新pos值
	}
	iterator end=_finish-1;
	while(end>pos)
	{
		*(end+1)=*(end);
		--end;
	}
	*pos=val;
	_finish++;
	return pos;
}

erase函数

iterator erase(iterator pos)
{
	assert(!empty());
	assert(pos >= _start);
	assert(pos < _finish);
	iterator ch=pos+1;
	//pos位置后的数据向前挪动
	while(ch<_finish)
	{
		*(ch-1)=*ch;
		ch++;
	}
	_finish--;
	return pos;
}

默认成员

在这里插入图片描述

构造函数1

无参构造函数,默认值写在初始化列表中

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

构造函数2

用Input的迭代器 [first,last)初始化,Input可以是任意类型,故使用模板

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

构造函数3

构造vector中含有n个值为val的元素,可以先用reserve,再push_back

 vector (size_type n, const value_type& val = value_type()):_start(nullptr)
	, _finish(nullptr)
	, _endofstorage(nullptr)
 {
 	reserve(n);
 	for (size_t i = 0; i < n; i++) //尾插n个值为val的数据到容器当中
	{
		push_back(val);
	}
}
 	

拷贝构造

vector(const vector<T>& v)
	:_start(nullptr)
	,_finish(nullptr)
	,_endofstorage(nullptr)
{
	_start = new T[v。capacity()];
 
	//将v中的数据一个个拷贝过来
	for (size_t i = 0; i < v.size(); i++)
	{
		//不可以使用memcpy,memcpy只能拷贝内置类型,无法处理自定义类型
		_start[i] = v[i]; //如果v中的元素是自定义类型,那么会调用其拷贝构造函数
	}
	_finish = _start + v.size(); 
	_endofstorage = _start + v.capacity(); 
}

拷贝容器内数据时,不能使用memcpy拷贝
在这里插入图片描述
当vector中存储的中string的时候,使用memcpy将v4里的每一个string调用拷贝构造,分别拷贝v3里的元素,_str指向同一个string。拷贝好之后释放原容器空间,原容器中存储的每个string在释放的时候会调用string的析构函数,将其指向的字符串也会进行释放,使得vector中每个元素指向的空间就是一块已经被释放的空间,访问该容器的时候也就是对非法空间的访问。

赋值运算符重载

vector<T>& operator=(vector<T> v) //编译器接收右值的时候自动调用其拷贝构造函数
{
	swap(v); //交换这两个对象
	return *this; //支持连续赋值
}

析构函数

~vector()
{
	delete[] _start;
	_start=_finish=_endofstorage=nullptr;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值