C++初阶 —— vector类

vector模板,初学者必读 vector vector 称为向量,是一种类模板,其声明包含在头文件< vector>中,所以使用veto 时需要包含头文件< vector> 。 vector是一种支持高效地随机访问和高效地向尾部插入新元素的容器,它一般实现为一 个动态分配的数组,所以在程序开发过程中,使用vector作为动态数组是非常方便的 类 似于数组, vector分配连续的存储空间存储数据,个相邻数据在存储空间上是相邻的。所 以, vector可以像数组一样实现随机访问。 与数组不同的是, v. 阅读详情

目录

一,标准库中的vector类模板

二,vector类的常用接口

构造函数

容量操作函数

访问及遍历操作函数

增删查改

迭代器失效问题

三,vector深度剖析及模拟实现


一,标准库中的vector类模板

vector类模板

  • vector表示可变大小数组的序列容器,类似string也是利用动态数组实现的;
  • vector可使用下标对元素进行访问,和数组一样高效;但又不像数组,其大小是可以动态变动的(大小会被容器自动处理);
  • 新插入元素时,可能需重新分配数组大小,以增加存储空间;其原理为分配一个新数组,并将全部元素移到新数组;这是一个相对代价高的任务,因此每个新元素加入,vector并不会每次都重新分配大小;
  • vector会分配一些额外的空间以适应可能的增长,不同的库采用不同的策略权衡空间的使用和分配;但无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入元素时是在常数时间的复杂度完成;
  • 与其他动态序列容器相比(deques, lists and forward_lists),vector在访问元素时更加高效,在末尾添加和删除元素时相对高效;对于其他不在末尾的删除和插入,效率较低;比起lists和forward_lists,缺乏统一的迭代器和引用;

注:在使用vector类时,必须包含#include<vector>头文件,其命名空间为std;string 可大致理解为是 vector<char> 的特化版本;

二,vector类的常用接口

构造函数

  • vector(),无参构造;
  • vector(size_type n, const value_type& val=value_type()),构造并初始化n个val;
  • vector(const vector& x),拷贝构造;
  • vector(inputlterator first, inputiterator last),使用迭代器进行初始化;
int main()
{   
    vector<int> v; //(1)默认无参构造

    vector<int> v1(4); //(2)创建4个元素,默认值为0;
    vector<int> v2 = (vector<int>)4; //(2)有关键字explicit修饰,无法隐式转化int->vector<int>
    vector<int> v3(4, 10); //(2)创建4个元素,值指定为10

    vector<int> v4(v1); //(4)拷贝构造
    vector<int> v5(v1.begin(), v1.end()); //(3)迭代器初始化,数据类型要匹配

    //(6)列表初始化C++11
    vector<int> v6{ 1,2,3,4 };
    vector<int> v7 = { 1,2,3,4 }; //与v6等价
}

容量操作函数

size获取数据个数;
capacity获取容量大小;
resize改变vector的size;
reserve改变vector的capacity;
empty判断是否为空;
clear清空有效字符,size为0,capacity不变;
int main()
{
	vector<int> v(4, 10); 
	cout << v.size() << " " << v.capacity() << endl;

	v.reserve(10);
	cout << v.size() << " " << v.capacity() << endl;

	v.resize(20);
	cout << v.size() << " " << v.capacity() << endl;

	cout << v.empty() << endl;
	return 0;
}

访问及遍历操作函数

operator[]访问指定元素,像数组一样;
at访问指定元素,会边界检查,超出会抛异常;
front访问第一个元素,如容器为空将导致未定义行为;
back访问最后一个元素,如容器为空将导致未定义行为;
begin+end获取第一个数据位置的iterator/const_iterator,
获取最后一个数据的下一个位置的iterator/const_iterator;
rbegin+rend获取最后一个数据位置的reverse_iterator,
获取第一个数据的前一个位置的reverse_iterator;
int main()
{
	vector<int> v{1,2,3,4}; //列表初始化

	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	//迭代器
	vector<int>::iterator it = v.begin(); //或auto it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	for (auto i = v.rbegin(); i != v.rend(); i++)
		cout << *i << " ";
	cout << endl;

	//范围for
	for (auto i : v)
	{
		cout << i << " ";
	}
	return 0;
}

增删查改

push_back尾插;
pop_back尾删;
assign赋新值以替代当前值;
insert在pos位置前插入元素;
erase删除pos位置的元素,或连续元素[first,last);
swap交换两vector的数据空间,两vector对象都会改变,有同名的非成员函数;
find查找(算法模块实现,不是vector的成员接口);
int main()
{
	vector<int> v(4, 10);
	vector<int> v2(2, 3);
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.pop_back();
	v.insert(v.begin(), 1);
	v.insert(v.begin(), 5, 2);
	v.erase(v.begin());
	v.erase(v.begin(), v.begin() + 5);
	v.swap(v2);
	swap(v, v2);
	find(v.begin(), v.end(), 2); //算法模块实现的,返回迭代器
	sort(v.begin(), v.end());
	return 0;
}

迭代器失效问题

        迭代器的主要作用,就是让算法能够不用关心底层数据结构(其底层实际是指针,或是对指针进行了封装),如vector的迭代器就是原生指针T*;因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁,而使用一块已经被释放的空间,程序会崩溃;

可能导致迭代器失效的操作:

  • 会引起底层空间改变的操作,都有可能使迭代器失效,如resize、reserve、insert、assign、push_back等;
  • 指定位置元素删除操作erase;

注:在使用前,对迭代器重新赋值即可解决迭代器失效的问题;

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	auto pos = find(v.begin(), v.end(), 2);
	if (pos != v.end())
	{
		v.insert(pos, 20);
        //或 v.erase(pos);
	}
	//insert导致增容,pos任指向原释放的位置,迭代器失效
	//即使没有增容,依然认为迭代器失效,因为意义改变了,不在指向原来的值
    //但g++没有报错,检查环境不一样
    //失效后,不要*pos访问,会出问题;
	cout << *pos << endl;
	*pos = 10;
	return 0;
}

三,vector深度剖析及模拟实现

namespace myvector
{
	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; }

    private:
		iterator _start; //起始位置;
		iterator _finish; //size()位置,即末尾的下一个位置;
		iterator _endofstorage; //capacity()位置,即最后一个位置之后的位置;

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

		//InputIterator表示不仅限于iterator
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			while (first != last) {
				push_back(*first);
				++first;
			}
		}
		//传统写法1
		//vector(const vector<T>& v) //或vector(const vector& v) 
        //{
		//	_start = new T[v.capacity()];
		//	memcpy(_start, v._start, sizeof(T) * v.size());
		//	_finish = _start + v.size();
		//	_endofstorage = _start + v.capacity();
		//}
		//传统写法2(推荐)
		//vector(const vector<T>& v)
		//	:_start(nullptr)
		//	, _finish(nullptr)
		//	, _endofstorage(nullptr)
		//{
		//	reserve(v.capacity());
		//	for (const auto e : v) {
		//		push_back(e);
		//	}
		//}
		//现代写法
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);
		}
		 
		//传统写法
		//vector<T>& operator=(const vector<T>& v) {
		//	if (this != &v) {
		//		delete[] _start;
		//		_start = _finish = _endofstorage = nullptr;
		//		reserve(v.capacity());
		//		for (const auto e : v) {
		//			push_back(e);
		//		}
		//	}
		//	return *this;
		//}
		//现代写法
		vector<T>& operator=(vector<T> v) {
			swap(v);
			return *this;
		}

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

    //******************************************************
		void reserve(size_t n) {
			if (n > capacity()) {
				size_t sz = size();
				T* tmp = new T[n];
				memcpy(tmp, _start, sizeof(T) * sz); //不安全

                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 {
				if (n > capacity())
					reserve(n);
				while (_finish < _start + n) {
					*_finish = val;
					++_finish;
				}
			}
		}

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

		void push_back(const T& x) {
			//if (_finish == _endofstorage)
			//{
			//	size_t newcapacity = capacity() ? capacity() * 2 : 4;
			//	reserve(newcapacity);
			//}
			//*_finish = x;
			//++_finish;

			insert(end(), x);
		}
		 
		void pop_back() {
			//assert(_finish != _start);
			//--_finish;

			erase(--end());
		}

		iterator insert(iterator pos, const T& val) {
			assert(pos >= _start && pos <= _finish);
			if (_finish == _endofstorage) {
				size_t len = pos - _start;
				size_t newcapacity = capacity() ? capacity() * 2 : 4;
				reserve(newcapacity);
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (pos <= end) {
				*(end + 1) = *end;
				--end;
			}
			*pos = val;
			++_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 swap(vector<T>& v) {
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}
		size_t size() const {
			return _finish - _start;
		}
		size_t capacity() const {
			return _endofstorage - _start;
		}

	};
}

C++初阶:STL之vector类模板 阅读详情

相关推荐

C++初阶—vector类

(constructor)构造函数声明接口说明vector()(重点)无参构造构造并初始化n个val(重点)拷贝构造使用迭代器进行初始化构造。

Awkwardx的博客 1130

[c++基础]-vector类

本期学习目标: 了解vector类的基本用法,刨析迭代器失效问题,刨析深浅拷贝问题,模拟实现vector。

分享技术 6766

【C++STL基础入门】vector向量基础使用

C++STL(Standard Template Library)是C++标准库中的一部分,提供了一组通用的模板容器和算法,以及一些有用的功能。其中,vector是STL中最重要且常用的容器之一。它类似于数组,但提供了更多的功能和灵活性。本文将详细介绍vector的基本使用方法,帮助读者快速入门。这行代码的含义是在C++中定义了一个名为vec的变量,它的类型是vector,也就是一个整数向量。vector:这是一个模板类,用来表示存储整数的向量。

m0_62599305的博客 2433

c++ - 第9节 - vector类

1.标准库中的vector类1.标准库中的vector类注:1. vector是表示可变大小数组的序列容器。2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。

qq_45113223的博客 2071

某头部能源集团“数据治理”到“数智应用”跃迁案例剖析

本次案例能源企业实现了从“数据可用”到“指标驱动”再到“智能决策”的全链条升级,标志着集团在数字化、智能化治理能力上的系统跃升,构建起面向未来的数智管理新范式。

a958014226的博客 1257

ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps8) failed -> CUDA_ERROR_DEINITIALIZED: driver shutting down

ffplay -vcodec h264_cuvid sample_720p-2.h264 [quantum6@freeswitch freeswitch]$ ffplay -vcodec h264_cuvid sample_720p-2.h264 ffplay version 4.3.1 Copyright (c) 2003-2020 the FFmpeg developers built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-44) .

柳鲲鹏 2404

C++初阶:vector类

C++ vector模拟实现

weixin_63143943的博客 766

软件自动化测试脚本如何编写,编写自动化测试脚本的几点注意事项

我们需要自动化测试脚本的原因:1、验收测试是一项非常复杂和费力的被用来确保软件质量的环节。它的目的就是使软件能得到充分运行并且能使其符合原始需求。2、测试的目的无非就是满足了两个结果:测试通过或测试不通过。为了能实现每个测试结果,必须要明确每个测试用例。并且对于整个系统而言在合同中必须定义测试用例的失败标准,而且这个失败标准数必须是可接受的。3、测试用例的通过条件必须有一个清晰的标准,标准可以被定...

weixin_39575775的博客 2251

C++初阶-vector类的模拟实现

因为增容中使用了memcpy,memcpy导致了问题的出现,因为memcpy是按字节拷贝的,它本质上造成了浅拷贝问题,memcpy使新旧空间都指向了一份数据,旧空间释放后,它指向的对应数据也被释放,而新空间指针还是指向这份旧空间,这就造成了非法访问,所以新空间与旧空间不应该指向同一份数据,应该不用memcopy,写成。(1)释放原空间,新开一块容量和v一样大的空间,更新_start,_finish,_end_of_storage。

sushang的博客 1184

C#+Winform+OpenCvSharp实战:5步搞定工业视觉检测框架(附源码下载)

本文详细介绍了如何使用C#、Winform和OpenCvSharp构建工业视觉检测框架,通过5个关键步骤实现高效、稳定的视觉检测系统。内容涵盖环境配置、相机集成、核心算法实现、系统集成与通信,以及部署优化,帮助开发者快速掌握工业视觉检测技术,提升检测精度和效率。附完整源码下载,助力工业数字化转型。

pz89012345的博客 550

Open3D 三维重建-Delaunay Triangulation (德劳内三角剖分)

德劳内三角剖分(Delaunay Triangulation)是一种用于从一组点生成三角形网格的算法。它的特点是使得生成的三角形尽量接近等边三角形,即最大化最小角度,避免生成细长的三角形。

纵马踏花向自由 2502

【C++初阶】一篇手撕vector类

vector 是表示可变大小数组序列容器。就像数组一样,vector 也采用连续的存储空间来存储元素。也就意味着可以采用小标对 vector 的元素进行访问,和数组处理一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。本质讲,vector 使用动态分配数组来存储它的元素。当新元素插入时,为了增加存储空间,这个数组需要被重新分配大小。其做法是,分配一个新的数组,然后将全部元素移到这个数组。

2201_75642960的博客 1530

深度学习论文: Towards Total Recall in Industrial Anomaly Detection

在大规模工业制造中,能够准确检测出有缺陷的零件至关重要。我们在这项工作中面临的一个特殊挑战是冷启动问题:仅使用正常的示例图像来训练模型。虽然可以针对每个类别手动设计解决方案,但我们的目标是构建能够自动适用于多个任务的系统。最佳的方法是将ImageNet模型的嵌入特征与异常检测模型结合起来。在本文中,我们在这一研究基础上进行了扩展,并提出了PatchCore,它利用了一个具有最大代表性的正常补丁特征内存库。通过这种方法,我们能够更好地解决冷启动问题,并提高系统在多任务上的性能。

mingo_敏 1875

【C++初阶】vector类常用接口与模拟实现

本文介绍了C++ STL中vector容器的基本使用。主要内容包括:vector的定义和构造方法、三种遍历方式(下标、迭代器、范围for)、容量操作(resize/reserve等)、增删查改接口(push_back/insert/erase等)。特别展示了vector存储vector实现二维数组的功能,并演示了使用[][]访问元素的方法。通过代码示例详细说明了各接口的使用场景和注意事项,如resize改变size但不缩容的特性等。

Z2382430464的博客 983

​非线性分析-增加位移量可能出现下面错误。虽然求解无法在所有时间点完成,但在某些点上仍能够求解部分结果。请参阅“帮助系统”中的故障排除,以了解更多信息详情。由于受约束,规划求解引擎无法收敛

基于收敛状态拆分载荷步‌:在已收敛的载荷步基础上,将未收敛的关键区域拆分为更细的子步,比如在载荷突变点前设置5~10个子步,逐步加载。替换冲突约束为弱约束‌:若存在约束冲突,将刚性约束替换为弱弹簧约束(刚度设为1e-6~1e-4),既限制刚体位移,又不影响结构的变形自由度,命令流:SPRING, NODE, K, 1e-6。部分区域约束完整,但存在未被约束的刚体自由度,或约束类型与大变形/接触逻辑冲突,比如某部件的位移约束在初始阶段有效,但大变形后约束位置脱离实际受力点,导致求解器在该阶段无法收敛。

qq_15963745的博客 144

vue3:html2canvas+jspdf将页面以A4导出为PDF文件,解决内容截断+在分页处截断问题详细排查和解决教程(jsPDF + html2canvas A4分页截断、内容分页时存在截断)

html2canvas + jsPDF 解决内容截断问题,vue3 jspdf-html2canvas生成多页pdf防截断处理(包含代码),vue3解决html2canvas + jsPDF导出pdf分页内容截断问题,jsPDF + html2canvas A4分页截断 完美解决方案(含代码 + 案例),html页面导出pdf截断问题,html2canvas 与 jspdf 相结合生成 pdf 内容被截断的终极解决方案,提供html2canvas+jsPDF将HTML页面以A4纸方式导出为PDF后,内容分页

✅ 精选推荐文章 2243

C++初阶】4.C++ vector类详解

类似于C语言的二级指针的关系,因此,第一层[]重载是找到对应的vector,第二层才是找到对应的int。在上期我们了解了string及其模拟实现,而vector是极其类似的东西,很多操作几乎一样。,但是由于传参int在函数结束后会销毁,因此我们传地址,直接在远处它的根上改,因此要传给我们。,同时,我们需要一个数组知道每一个一维数组的int个数有多少,因此需要一个。: 由于杨辉三角为二维数组,参考我们之前讲的二维vector,首先。接着,由于评测的需要,我们需要知道这个。,但同理,需要传地址,因此需要一个。

2509_93923260的博客 353

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

C++初阶:模拟实现vector类

既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy。是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中。构建动态二维数组时与上图实际是一致的。实现代码+测试样例:vector.h。进行的拷贝,以下代码会发生什么问题?类型的,每行没有包含任何元素,如果n。如果拷贝的是自定义类型的元素,实现代码:vector.h。的拷贝实际是浅拷贝。个元素,每个元素都是。

qq_71925940的博客 578

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C++初阶学习——探索STL奥秘——标准库中的vector类

vector详解

Joker10085的博客 1230

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【C++初阶】4.C++ vector类详解(含模拟实现及其代码)

目录Vector1. 构造2. 遍历3. 相关接口1. Size,capacity,empty,reserve2. Resize3. insert和erase4. 全局swap5. 比大小支持6. []重载和c语言区别Vector 模拟实现1. 迭代器定义(依旧用指针充当)2. 类元素3. 迭代器4. 大小相关5. 尾插6. Reserve本来写法修改7. 尾删8. []重载9. insert10. 临时打印函数11. 通用find函数12. 迭代器失效13. erase14. resize15. 构造函数

m0_68617924的博客 821

【C++初阶】vector类的常用操作、题目、模拟实现和迭代器失效问题

vector的文档说明vector 是表示可变大小数组的序列容器。vector 就像数组一样,也采用的连续空间来存储元素,这也意味着可以采用下标对 vector 的元素进行访问。vector 与普通数组不同的是,vector 的大小是可以动态改变的。当 vector 需要重新分配大小时,其做法是,分配一个新的数组,然后将全部元素移到这个数组当中,并释放原来的数组空间。vector 分配空间策略:vector 会分配一些额外的空间以适应可能的增长,因此存储空间比实际需要的存储空间一般更大。

Stark_Skywalker的博客 1283
上一篇: C++初阶 —— string类
下一篇: C++初阶 —— list类
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值