C++-----vector

这篇具有很好参考价值的文章主要介绍了C++-----vector。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本期我们来学习C++中的vector,因为有string的基础,所以我们会讲解的快一点

目录

vector介绍

vector常用接口

构造函数

sort

迭代器 

size,max_size,capacity,empty

reserve和resize

front和back

data

insert和erase

find

swap和clear

assign

vector扩容机制

vector模拟实现

全部代码


vector介绍

C++-----vector,c++,开发语言

 1. vector是表示可变大小数组的序列容器。

2. 就像数组一样, vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对 vector 的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3. 本质讲, vector 使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector 并不会每次都重新分配大小。
4. vector 分配空间策略: vector 会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5. 因此, vector 占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
6. 与其它动态序列容器相比( deque, list and forward_list ), vector 在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list forward_list统一的迭代器和引用更好

简单理解,vector就是一个数组,顺序表 

C++-----vector,c++,开发语言

我们先简单写一点代码来了解一下, 我们用三种方法遍历vector

 我们看代码里我们定义vector时,是vector<int> v; 是类模板的实例化

C++-----vector,c++,开发语言

我们可以用vector代替string吗?答案是不可以,首先,他俩的结构就不相同,string结尾是有\0的,可以更好兼容C语言,vector是没有的。string的接口是比vector更丰富的,比如+=,比较大小等等

C++-----vector,c++,开发语言

vector里是可以放string的,我们这里有三种插入方式,第一种就是常规的,第二种是借助匿名对象,但我们最喜欢的是第三种,是单参数的构造函数支持隐式类型转换

C++-----vector,c++,开发语言

还可以存vector,这里就是二维数组了

vector常用接口

C++-----vector,c++,开发语言

 我们上面注意到,vector是一个模板,我们看第二个模板参数Alloc,他是一个=空间配置器,也就是一个内存池,stl所有容器都用的这个内存池,因为需要频繁是申请释放空间,要提升效率

这里是给了默认参数的,如果我们感觉他的不好,我们可以自己写一个传过去,不过我们平时是不需要管的,因为他的那个就很好了

构造函数

C++-----vector,c++,开发语言

 第一个是全缺省的,第二个是n个value初始化,后面有个value_type,这个是typedef出来的

C++-----vector,c++,开发语言

其实就是T,这些在文档里都有介绍 

还有迭代器的初始化和拷贝构造,下面我们来使用一下

C++-----vector,c++,开发语言

我们使用n个value的进行初始化 

C++-----vector,c++,开发语言

我们看迭代器里有个inputiterator,并且是一个模板,这是一个模板区间,但不一定是vector,我们可以给其他类型,只要按迭代器的规范使用就行

C++-----vector,c++,开发语言

 这里最后一行打出来的为什么是数字?其实是整形提升,把char转换为了int,变成了ASCII码

C++-----vector,c++,开发语言

我们把这里改成char就可以了

C++-----vector,c++,开发语言

 还可以这样初始化

总结上面的,可以用自己类型的迭代器,其他类型的迭代器,还有数组来初始化,这个数组本质是指针,迭代器的行为就是模拟的指针,所以都是可以的

sort

C++-----vector,c++,开发语言

 stl是容器和算法,容器和算法是分开的,容器是存储数据,算法是处理数据,比如查找,排序等等,算法通过迭代器来访问容器里的数据,这里的两个sort底层使用的是快排,他不仅仅只作用于vector,只要符合条件的都可以使用

要使用算法,要先加头文件#include<algorithm>

C++-----vector,c++,开发语言

 这里我们是升序,如果想排降序,我们要用第二个sort,我们看第三个参数Compare comp

这里我们可以自己写,也可以用库里面的

C++-----vector,c++,开发语言

我们先学习如何使用,我们创建一个greater传过去就可以了 

C++-----vector,c++,开发语言

而且我们更推荐使用匿名对象,这样更舒服 

C++-----vector,c++,开发语言

我们上面的string也是可以用sort的 

C++-----vector,c++,开发语言

我们上面的数组a也是可以使用的

下面我们来看迭代器

迭代器 

C++-----vector,c++,开发语言

 第一个是读写迭代器,第二个const是只读迭代器

C++-----vector,c++,开发语言

还有反向迭代器

C++-----vector,c++,开发语言

反向迭代器会使排序从变为降序排序 

size,max_size,capacity,empty

C++-----vector,c++,开发语言

C++-----vector,c++,开发语言

这些过于简单,我们就不再多说 

reserve和resize

C++-----vector,c++,开发语言

reserve是扩容

C++-----vector,c++,开发语言

我们看这种错误的写法,这里vector里size是0,capacity是10,方括号是operator[ ](size_t i),他里面有assert(i<_size),就会崩溃,reserve只是扩容,如果我们想这样访问,是要用resize的,他会把size也设为10

C++-----vector,c++,开发语言

就像这样 

如果就像要用reserve,下面的插入数据就不能用方括号,而是要用push_back

operator[ ]和at

C++-----vector,c++,开发语言

at是抛异常,operator[ ]是断言,断言更暴力一些 

front和back

C++-----vector,c++,开发语言

 这两个接口也非常简单,就是第一个元素和最后一个,其实我们用方括号0,和方括号size-1就可以完成了

data

C++-----vector,c++,开发语言

 这个接口和string里的c_str非常像,返回一个数组指针

push_back和pop_back

C++-----vector,c++,开发语言

 我们发现没有头插头删,只有尾插尾删,原因是头插头删是需要挪动数据的,和string是一样

但我们要头插头删也是可以的

insert和erase

C++-----vector,c++,开发语言

C++-----vector,c++,开发语言

  使用insert和erase就可以了

C++-----vector,c++,开发语言

 我们进行头插头删

C++-----vector,c++,开发语言

删除第三个位置的 

如果我们想删除2,那我们可以和find配合,但是我们找了半天文档,发现没有find

find

C++-----vector,c++,开发语言

这是因为其实find在算法里 ,而string是有自己的find的,因为string的find比较多样化,而vector是要和别的容器复用的

我们使用find要传一个迭代区间,是左闭右开,传[ first , last ),找到返回位置,找不到返回last

C++-----vector,c++,开发语言

比如我们这里删除了2 

C++-----vector,c++,开发语言

这么长的是可以用auto替代的 

C++-----vector,c++,开发语言

如果我们想要删除所有的3,这样写缺崩溃了 ,原因是这里涉及迭代器失效的问题,这个知识点我们在未来底层实现来讲

C++-----vector,c++,开发语言

我们可以从头开始找,但是效率低 ,这个问题我们暂时保留

swap和clear

C++-----vector,c++,开发语言

 一个是交换,一个是清理,也是非常简单,这里就不多说

assign

C++-----vector,c++,开发语言

 清空当前的值然后重新赋值

C++-----vector,c++,开发语言

比如我们之前有很多数,然后我们assgin,就变成了10个1 ,这个函数我们也不常用

vector扩容机制

// 测试vector的默认扩容机制
void TestVectorExpand()
{
 size_t sz;
 vector<int> v;
 sz = v.capacity();
 cout << "making v grow:\n";
 for (int i = 0; i < 100; ++i) 
 {
 v.push_back(i);
 if (sz != v.capacity()) 
 {
 sz = v.capacity();
 cout << "capacity changed: " << sz << '\n';
 }
 }
}

C++-----vector,c++,开发语言

 在vs下vector基本是1.5倍扩容,在Linux下是2倍扩容

C++-----vector,c++,开发语言

 两个扩容还是有区别的,大家了解一下即可

vector模拟实现

我们先来简单看看vector官方的源代码

C++-----vector,c++,开发语言

C++-----vector,c++,开发语言

 我们发现,vector的迭代器使用的就是指针,因为vector的空间是连续的,就是一个数组

再看他的成员,发现和我们想的不太一样,我们设想的是有个size,capacity等等

C++-----vector,c++,开发语言

我们再看他的构造函数, 第一个构造就是把三个指针初始化为空了,剩下的我们也看不出什么

C++-----vector,c++,开发语言

 我们看push_back,这个看起来就顺眼多了

我们看finish,是结束的意思,而storage是存储的意思,所以我们可以猜测,finish指向的是数据结束的位置,就像size,end _of_storage指向空间的结束,就像capacity

我们再根据if和else里的逻辑来猜测,construct是什么我们暂时不知道,但是看到++finish,我们就大概可以确认我们前面的猜想是合理的,所以if里的语句是空间没满的逻辑,else里是满了的逻辑,满了一般会进行扩容,我们再找找insert_aux

C++-----vector,c++,开发语言

 我们看ifelse,这里再次判断是因为inset不是仅仅给pushback使用,还有可能是别人直接调用等等,所以按照我们前面的逻辑此时我们应该进入else,这里面是非常复杂的,有一个old_size,是二倍增长的,我们还可以看到copy什么什么的,这里就是扩容的逻辑了

C++-----vector,c++,开发语言

我们再看看reserve,我们看最后三句,tmp是新开的空间(上面有个什么什么copy,数据拷贝过去了),tmp给了start,tmp+oldsize给了finish,n是空间的大小,又有end_of_storage,allocate是申请空间,那么deallocate就是释放空间,

 C++-----vector,c++,开发语言

 我们看construct和destroy,下面有一个定位new,是用来显示调用构造函数的,这里没有直接赋值等等的原因是,我们的空间都是空间配置器,也就是内存池开的,如果是自定义类型,比如vector<string>,里边如果有数据等等,是不能直接赋值的,不然是会崩的,这里就会把T推演为string,然后初始化,出了作用域还要调用析构函数

这里本质就是为了提高效率,其实使用new和delete就可以了

C++-----vector,c++,开发语言

 看了这么多,下面我们开始模拟实现

namespace bai {
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		vector()
			:_start(nullptr)
			,_finish(nullptr)
			,_endofstorage(nullptr)
		{}

		void push_back(const T x)
		{

		}
	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};
}

首先我们把框架搭建好,我们按照源码那样来写,模拟一样,看看他们那样写有什么好处

        void push_back(const T& x)
		{
			if (_finish == _endofstorage) //满了扩容
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			++_finish;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}
		size_t size() const
		{
			return _finish - _start;
		}

我们实现一下pushback,以及capacity和size

        void reserve(size_t n)
		{
			if (n > capacity())
			{
				//扩容
				T* tmp = new T[n];
				if (_start)//原空间不为空则进行拷贝
				{
					memcpy(tmp, _start, sizeof(T) * size());
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + size();
				_endofstorage = _start + n;
			}
		}

再实现一下reserve

        iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}

我们再补充一下迭代器,此时我们就可以简单测试代码了

C++-----vector,c++,开发语言

我们运行发现代码崩溃了,我们进行调试

 C++-----vector,c++,开发语言

最后发现在finish这里出现了问题 ,原因就是size有问题,最开始的时候三个成员都是空的,然后start指向我们创建的tmp空间,finish和start指向的不在一块空间

我们的第一种解决方法是这里的finish=tmp+size();,同时交换finish和start的顺序

C++-----vector,c++,开发语言

C++-----vector,c++,开发语言

 下面我们再看第二种方法

C++-----vector,c++,开发语言

第二种方法就是我们提前保存一下size 

C++-----vector,c++,开发语言

 没有问题

        ~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}

我们继续补充,首先是析构函数

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

还有我们经常使用的方括号,我们再测试一下

C++-----vector,c++,开发语言

没有问题

C++-----vector,c++,开发语言

 还有记得补充const迭代器 

        void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			if (_finish == _endofstorage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

还有insert,不过此时的insert是有bug的

C++-----vector,c++,开发语言

C++-----vector,c++,开发语言

我们多次pushback,有时候会出现问题,有时候不会,这就是迭代器失效 

4和8的时候都是扩容的节点,一旦扩容,我们要把数据拷贝到新的空间,然后释放旧空间,此时我们insert里的pos就不对了,start,finish都指向了新的空间,而pos还在旧空间,就变成了野指针

C++-----vector,c++,开发语言

我们需要更新一下pos,这样就没有问题了

 C++-----vector,c++,开发语言

有insert我们就可以复用了,就不需要pushback了

 我们上面解决了内部迭代器失效的问题,下面还有外部迭代器失效问题

C++-----vector,c++,开发语言

 C++-----vector,c++,开发语言

为什么第一个是310,第二个是300呢?还没有报错

 因为insert是传值传参,pos改变不会影响p,但是给pos加引用就编译不通过了

我们的begin是传值返回,返回的是他的拷贝,是临时变量,临时变量具有常性

所以我们在外部一定要记住,insert的迭代器可能会失效,但是什么情况失效我们不知道,因为平台不同,扩容机制不同,扩容的时候会失效,所以insert以后就不要使用形参迭代器了,因为他可能失效了,我们修改的话可能是一个高危行为

C++-----vector,c++,开发语言

如果真的要用,就用返回值吧 ,库里面的也有迭代器失效的问题,我们现在模拟的就是一样的

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

我们再实现一下erase,然后测试一下

C++-----vector,c++,开发语言

没有问题,这里有迭代器失效问题码?

C++-----vector,c++,开发语言

其实还是有问题的 ,所以erase迭代器也是会失效的

如果我们使用库里面的,使用vs的话就会直接报错,也就是说erase以后迭代器失效不能访问,vs会进行强制检查,直接报错

C++-----vector,c++,开发语言

 如果在Linux下的话就变成了这样,二者的结果是不一样的

不过在Linux下,有些情况是非常危险的,比如我们要删除所有的偶数

C++-----vector,c++,开发语言

 C++-----vector,c++,开发语言

 看着没有问题,其实这是一个偶然,我们改变一下测试用例

C++-----vector,c++,开发语言

 C++-----vector,c++,开发语言

 就会变成这样

C++-----vector,c++,开发语言

如果最后一个位置是6 

C++-----vector,c++,开发语言

这里就是一个段错误,出了一个大问题,在vs下上面这三种情况都是直接报错的

我们看第二种情况,1,2,2,3,4,5的情况

it指向第一个2的时候,我们进行删除,就变成了1,2,3,4,5,此时it还是指向2的,我们没有进行检查,然后++it,it就指向了3,就跳过了第二个2

再看第三种情况,1,2,2,3,4,5,6的情况

前面和第二种是一样的,先是错过了第二个2,指向4的时候,删除4,然后往前挪,变成1,2,3,5,6,,此时是指向5的,然后++it,指向6,此时finish在it的下一个位置,我们要删除这个位置,是挪动后面的覆盖前面的,但是这里是最后一个位置,所以没有覆盖,会让finish--,到达6的这个位置,然后++it,此时it就在finish之后了,之后在循环条件里,it永远就不会等于end了,会不断往后走,不断的越界

C++-----vector,c++,开发语言

 有人可能会想加一个else,其实这样做还是有问题的,我们这样写在Linux下可以跑,但是如果换在vs下的话就出事了

C++-----vector,c++,开发语言

就直接崩溃了 ,++是没有问题的,问题在于下一次erase时,不管怎么解引用访问都是会报错的

C++-----vector,c++,开发语言

 (这里迭代器用的不是原生的指针,而是使用了封装,我们学完list后就可以理解了)

然后我们再走下一步就会报错了

我们看官方文档的话,官方是考虑了这种情况的,我们要使用返回值来解决

C++-----vector,c++,开发语言

C++-----vector,c++,开发语言 返回的是刚被删除的元素的下一个位置

C++-----vector,c++,开发语言

 所以代码最后是这样写的,此时Linux和vs下都是可以跑的,问题也都解决了

C++-----vector,c++,开发语言

我们最后再修改一下我们的代码 

总结一下,vector的erase和insert使用迭代器对象后,不能再访问该迭代器,我们认为它失效,访问结果是未定义的

迭代器的失效可能是野指针问题,也可能是位置的问题

C++-----vector,c++,开发语言

我们再复用实现一下头删 

C++-----vector,c++,开发语言

还有resize,resize要给初始值,但是这里我们不能给0,因为T是什么我们不知道,有可能是string,也有可能是vector等等,所以这里我们这样写,这是一个匿名对象, 比如T是string,这里就会调用默认构造,不过这里如果是int,理论上不行的,因为int是没有构造函数的,但是有了模板后,C++等于对内置类型进行了升级,也支持内置类型有默认构造

C++-----vector,c++,开发语言

就像这样写都是没问题的 

        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;
				}
			}
		}

我们再测试一下

C++-----vector,c++,开发语言

没有问题 

        vector(const vector<T>& v)//拷贝构造
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			_start = new T[v.capacity()];
			memcpy(_start, v._start,sizeof(T)*v.size());
			_finish = _start + v.size();
			_endofstorage = _start + v.capacity();
		}

我们再来实现一下拷贝构造

C++-----vector,c++,开发语言

测试一下也没有问题 

        vector(const vector<T>& v)//拷贝构造
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			reserve(v.capacity());
			for (auto e : v)
			{
				push_back(e);
			}
		}

还可以这样写

        void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}
		vector<T>& operator=(vector<T> v)//赋值
		{
			swap(v);
			return *this;
		}

我们再完成一下赋值,使用swap来辅助一下

我们再看一个问题

C++-----vector,c++,开发语言

 此时是没有问题的

C++-----vector,c++,开发语言

但是多了一个就出问题了,我们分析问题应该在扩容上 

我们有一个vector,里面都是string,每个string都有str,size,capacity,每个string对象都是new出来的

现在我们要进行扩容,要开辟一个新的空间,也是new出来的

C++-----vector,c++,开发语言

 而我们的字符串(“1111”,“2222”这些)都在堆上面,我们原来的vector(上面的)都指向他们,现在扩容后要进行拷贝,我们的reserve,使用了memcpy,他会把上面的string每个字节都拷贝下来,导致新的空间里的string也指向了堆上面的这些字符串,然后旧的空间被delete,调用了析构函数,T是自定义类型,依次调用数组每个对象的析构函数,再释放整个空间,但是我们扩容后的新空间还指向堆上的这些空间

也就是说,vector是深拷贝,但是vector空间上的对象是string数组,使用memcpy导致string对象浅拷贝

C++-----vector,c++,开发语言

我们把reserve里的memcpy换成这样的代码就可以解决了

 我们在这个地方需要深拷贝,这里的本质调的是string的赋值

我们拷贝构造也有一样的问题(使用push_back的没有问题),使用的也是memcpy

C++-----vector,c++,开发语言

修改如上即可 ,如果T是string,我们调用的是string的赋值重载,实现string对象的深拷贝

涉及到深拷贝问题的还有vector<vector< >>

C++-----vector,c++,开发语言

 大家理解最好画图理解一下前面为什么那样修改代码

C++-----vector,c++,开发语言

我们再看vector里的这两个构造 

第一个是n个val初始化

C++-----vector,c++,开发语言

我们可以使用resize偷懒

C++-----vector,c++,开发语言 

 没有问题

第二个构造是用一个迭代器区间初始化

C++-----vector,c++,开发语言

我们先看参数,我们直接这样写是不好的,这样写只能使用vector的迭代器来初始化,我们看到之前是可以使用其他迭代器初始化的,比如string的,所以我们要换一种写法

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

 我们可以在类模板里套用类模板,是不是很神奇?

不过此时还有一些问题,我们在使用n个val初始化时会出现冲突

C++-----vector,c++,开发语言

这里会调用我们新写的inputiterator构造

C++-----vector,c++,开发语言

库里面为了解决这个问题还专门提供了方案 

C++-----vector,c++,开发语言

我们加一个int的即可 

全部代码

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

namespace bai {
	template<class T>
	class vector
	{
	public:
		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;
		}
		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			resize(n, val);
		}
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			resize(n, val);
		}
		//[first,last)
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector()
			:_start(nullptr)
			,_finish(nullptr)
			,_endofstorage(nullptr)
		{}
		
		vector(const vector<T>& v)//拷贝构造
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			_start = new T[v.capacity()];
			//memcpy(_start, v._start,sizeof(T)*v.size());
			for (size_t i = 0; i < v.size(); i++)
			{
				_start[i] = v._start[i];
			}
			_finish = _start + v.size();
			_endofstorage = _start + v.capacity();
		}
		//vector(const vector<T>& v)//拷贝构造
		//	:_start(nullptr)
		//	, _finish(nullptr)
		//	, _endofstorage(nullptr)
		//{
		//	reserve(v.capacity());
		//	for (auto e : v)
		//	{
		//		push_back(e);
		//	}
		//}
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}
		vector<T>& operator=(vector<T> v)//赋值
		{
			swap(v);
			return *this;
		}
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}
		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());
					for (size_t i = 0; i < size(); i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}				
				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}
		}
		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;
				}
			}
		}

		void push_back(const T& x)
		{
			/*if (_finish == _endofstorage) 
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			++_finish;*/
			insert(end(), x);
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}
		size_t size() const
		{
			return _finish - _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];
		}
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
				//解决pos迭代器失效
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos <= _finish);
			iterator it = pos + 1;
			while (it != _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;
			return pos;
		}
		void pop_back()
		{
			erase(--end());
		}
	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};
}

以上即为本期全部内容,希望大家可以有所收获

如有错误,还请指正文章来源地址https://www.toymoban.com/news/detail-593264.html

到了这里,关于C++-----vector的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 主流开发语言和开发环境介绍

    Tips:TIOBE排行榜是根据互联网上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如Google、Bing、Yahoo!)以及Wikipedia、Amazon、YouTube和Baidu(百度)统计出排名数据,只是反映某个编程语言的热门程度,并不能说明一门编程语言好不好,或者一门语言所编写的代码数

    2024年02月21日
    浏览(41)
  • 【C++ STL】vector类最全详解(什么是vector?vector类的常用接口有哪些?)

    目录 一、前言 二、什么是vector ? 💦 vector的基本概念 💦vector的作用是什么 💦总结 三、 vector的(一维)定义 四、vector(一维)常用接口的使用  💦vector的常见构造(初始化)  💦vector的遍历及迭代器的操作 ① operator[ ]  ② at ( )  ③迭代器  ③ 范围for   💦vector的常见容量操

    2024年02月03日
    浏览(41)
  • 鸿蒙的开发语言、工具以及开发环境。

    一、鸿蒙开发主要使用华为自主研发的鸿蒙操作系统(HarmonyOS)支持的语言进行应用开发。根据官方文档和资源,鸿蒙系统支持多种开发语言。 1. Java:作为鸿蒙系统原生支持的开发语言之一,Java在鸿蒙应用开发中占据重要地位,尤其是对于Android开发人员来说,可以较为容易

    2024年04月27日
    浏览(34)
  • STL 关于vector的细节,vector模拟实现【C++】

    _start指向容器的头,_finish指向容器当中 有效数据 的下一个位置,_endofstorage指向整个容器的尾 先开辟一块与该容器大小相同的空间,然后将该容器当中的数据一个个拷贝过来即可,最后更新_finish和_endofstorage的值即可。 深拷贝版本一: 注意: 不能使用memcpy函数 , 如果vec

    2024年02月15日
    浏览(45)
  • 【HarmonyOS北向开发】-05 ArkTS开发语言-ArkTS开发实践

    飞书原文档:Docs 

    2024年02月11日
    浏览(53)
  • idea插件开发-自定义语言00-开发导航

     源码 Initial Setup(初始化设置) ​​Registering a File Type​​​ :注册文件类型要实现一个自定义的语言必须要实现的,​​示例代码​​ ​​Implementing Lexer实现​​ :实现编程语言的语法分析器,​​示例代码​​ ​​Implementing Parser and PSI​​​:实现一个词法分析器

    2024年02月12日
    浏览(34)
  • 【C++庖丁解牛】STL之vector容器的介绍及使用 | vector迭代器的使用 | vector空间增长问题

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 vector的文档介绍 vector是表示可变大小数组的序列容器。 就像数组一样,vector也采用的连续存储空间来存

    2024年03月14日
    浏览(79)
  • 【开发语言】C语言与Python的互操作详解

    博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客内容主要围绕:        5G/6G协议

    2024年02月10日
    浏览(65)
  • Linux C语言开发(二)C语言数据类型

    目录 一.C语言概述 1.1 什么是C语言 1.2 C语言与Linux 1.3 C语言的特点 二.数据类型

    2024年01月17日
    浏览(39)
  • MCU嵌入式开发-硬件和开发语言选择

    主要考虑以下方面来决定是否需要RTOS支持: 需要实现高响应时的多任务处理能力 需要实现实时性能要求高的任务 需要完成多个复杂的并发任务 具备满足工控系统实时性要求的各项功能特性。通过它提供的硬件库、线程支持、中断支持等,可以完全控制微控制器的各个外设,实

    2024年02月12日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包