C++: vector

news2024/12/23 10:56:21

目录

1.vector的介绍

2.vector常用的接口 

1.vector构造

2.迭代器iterator的使用

3.vector空间增长

 4.vector的增删改查

3.vector模拟实现

如果在reverse时使用memcpy会怎么样?


1.vector的介绍

C++中的vector是一个动态数组容器,可以存储任意类型的数据。它提供了动态大小的数组功能,可以在运行时动态地增加或减少其大小。vector是C++标准模板库(STL)中的一部分,因此可以使用标准库中提供的许多函数和算法来操作它。

1. vector 是表示可变大小数组的序列容器。
2. 就像数组一样, vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对 vector 的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3. vector 分配空间策略: vector 会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存 储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是 对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
4. 与其它动态序列容器相比( deque, list and forward_list ), vector 在访问元素的时候更加高效,在末 尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率比较低。

2.vector常用的接口 

1.vector构造

1.vector();无参构造函数

2.vector(size_type n,const value_type&val=value_type());

构造一个包含 n 个元素的容器。每个元素都是 val 

3.vector(const vector&x); 拷贝构造。

4.vector(InputIterator first,InputIterator last);

用迭代器进行初始化构造            

2.迭代器iterator的使用

1.iterator begin();

返回指向vector中第一个元素的迭代器。

2.iterator end();

返回指向vector中最后一个元素下一个位置的迭代器。

3.reverse_iterator rbegin()

返回指向vector中最后一个元素位置的reverse_iterator

4.reverse_iterator end()

                                               

 返回指向vector中第一个元素的前一个位置位置的reverse_iterator

3.vector空间增长

1.size_type size();

返回数据个数

2.size_type capacity(); 

返回容量大小

3.bool empty();

判断是否为空

4.resize函数

如果 n 小于当前容器大小,则内容将减少到其前 n 个元素,删除超出的元素(并销毁它们)。

如果 n 大于当前容器大小,则通过在末尾插入任意数量的元素来扩展内容,以达到 n 的大小。如果指定了 val,则新元素将初始化为 val 的副本,否则,它们将初始化值。

如果 n 也大于当前容器容量,则会自动重新分配分配的存储空间。

5.reverse函数

请求vector容量至少足以包含 n 个元素。

如果 n 大于当前向量容量,则该函数会导致容器重新分配其存储,从而将其容量增加到 n(或更大)。

在所有其他情况下,函数调用不会导致vector容量不受影响。

capacity 的代码在 vs g++ 下分别运行会发现, vs capacity 是按 1.5 倍增长的, g++ 是按 2 倍增长的
reserve 只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector增容的代价缺陷问题。
resize 在开空间的同时还会进行初始化,影响 size。

 4.vector的增删改查

 1.push_back();尾插

2.pop_back();尾删

3.find();查找

find是算法模块实现,不是vector的成员接口

template<class InputIterator, class T>
  InputIterator find (InputIterator first, InputIterator last, const T& val)
{
  while (first!=last) {
    if (*first==val) return first;
    ++first;
  }
  return last;
}

4.insert();插入

通过在指定位置的元素之前插入新元素来扩展vector,从而有效地通过插入的元素数增加容器大小。

当且仅当新的vector大小超过当前vector容量时,这会导致自动重新分配分配的存储空间。

由于vector使用数组作为其基础存储,因此在vector以外的位置插入元素会导致容器将位置之后的所有元素重新定位到其新位置。与其他类型的序列容器(如列表或forward_list)对相同操作执行的操作相比,这通常是一种低效的操作。

5.erase();删除

从向量中删除单个元素 或一系列元素

由于vector使用数组作为其基础存储,因此擦除vector以外的位置的元素会导致容器在擦除段后将所有元素重新定位到其新位置。与其他类型的序列容器对相同操作执行的操作相比,这通常是一种低效的操作 

6.swap();交换

通过 x 的内容交换容器的内容,x 是另一个相同类型的vector对象。尺寸可能有所不同。

调用此成员函数后,此容器中的元素是调用之前位于 x 中的元素,x 的元素是位于 this 中的元素。所有迭代器、引用和指针对交换的对象仍然有效。

3.vector模拟实现

#pragma once
#include<assert.h>


namespace wjc
{
	template <class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;


		vector()
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
		}
		vector(const vector<T>& v)
		{
			reserve(v.capacity());
			for (const auto& e : v)
			{
				push_back(e);
			}
		}
		iterator begin()
		{
			return _start;
		}


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


		const_iterator end() const
		{
			return _finish;
		}
		size_t capacity()const
		{
			return _endofstorage - _start;
		}
		size_t size()const
		{
			return  _finish - _start;
		}


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


		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 oldsize = size();
				T* tmp = new T[n];
				if (_start)
				{
					/*memcpy(tmp, _start, sizeof(T) * oldsize);*/
					for (size_t i = 0; i < oldsize; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + oldsize;
				_endofstorage = _start + n;
			}
		}
		void resize(size_t n, T val = T())
		{
			if (n > size())
			{
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}




		void pop_back()
		{
			assert(size() > 0);
			--_finish;
		}
		void insert(iterator pos, T x)
		{
			assert(pos <= _finish);
			assert(pos >= _start);
			size_t len = pos - _start;
			if (_finish == _endofstorage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);//pos ʧЧ
				//posλ
				pos = _start + len;
			}
			memmove(pos + 1, pos, (_finish - pos) * sizeof(T));
			*pos = x;
			++_finish;
		}


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


		T& operator[](size_t pos)
		{
			assert(pos, size());
			return _start[pos];
		}
		const T& operator[](size_t pos)const
		{
			assert(pos, size());
			return _start[pos];
		}
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
	private:


		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};


}

如果在reverse时使用memcpy会怎么样?

1. memcpy 是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
2. 如果拷贝的是自定义类型的元素, memcpy 既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy 的拷贝实际是浅拷贝。
#include"vector.h"
int main()
{
	wjc::vector<string> v;
 	v.push_back("1111");
	v.push_back("2222");
	v.push_back("3333");
	v.push_back("4444");
	v.push_back("5555");
 	return 0;
}

运行这段代码会出现问题,因为插入4个元素后需要扩容,但是memcpy只是将一段内存空间中内容原封不动的拷贝到另外一段内存空间中,_start指向的空间已经释放了,也就是野指针,但是直到插入第5个元素_start依旧指向原来的空间,vector释放空间会导致同一片空间释放两次。

所以如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。最好开辟新空间来拷贝,如下面的方法:

void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t oldsize = size();
				T* tmp = new T[n];
				if (_start)
				{
					/*memcpy(tmp, _start, sizeof(T) * oldsize);*/
					for (size_t i = 0; i < oldsize; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + oldsize;
				_endofstorage = _start + n;
			}
		}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1405083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

element plus表格的表头和内容居中

文章目录 需求分析 需求 对于 element-plus 中的 table 进行表头和内容的居中显示 分析 单列的表头和内容居中 &#xff1a; 在对应的那一列加上align“center” 即可 <el-table-column prop"name" label"商品名称" align"center" />…

Golang 中如何实现 Set

在Go编程中&#xff0c;数据结构的选择对解决问题至关重要。本文将探讨如何在 GO 中实现 set 和 bitset 两种数据结构&#xff0c;以及它们在Go中的应用场景。 Go 的数据结构 Go 内置的数据结构并不多。工作中&#xff0c;我们最常用的两种数据结构分别是 slice 和 map&#…

安防视频监控EasyCVR平台HTTP-FMP4播放协议在分屏播放时的性能优化

安防视频监控EasyCVR平台兼容性强&#xff0c;可支持的接入协议众多&#xff0c;包括国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&#xff1a;海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等。平台能将接入的视频…

String对象的探究(new String到底创建了多少对象?)

String对象的探究 1. 前言&#xff08;String&#xff09;2. new String()到底创建了多少对象&#xff08;java8举例&#xff09;&#xff1f;2.1. new String("abc")&#xff1a;2/12.2. String str “a” "b" “c”&#xff1a;12.3. String abc &quo…

【MySQL源码】Seconds_Behind_Master是如何计算的

作为MySQL DBA&#xff0c;相信大家对参数 Seconds_Behind_Master 并不陌生&#xff0c;该字段的值可以通过 show slave status\G的输出&#xff0c;表示主从延迟的时间&#xff0c;单位为秒。监控主从延迟一般取这个值就足够了。0 表示无延迟&#xff0c;理想状态该值不要超…

JavaWeb之JavaScript-Vue --黑马笔记

什么是JavaScript&#xff1f; JavaScript&#xff08;简称&#xff1a;JS&#xff09; 是一门跨平台、面向对象的脚本语言。是用来控制网页行为的&#xff0c;它能使网页可交互。 JavaScript 和 Java 是完全不同的语言&#xff0c;不论是概念还是设计。但是基础语法类似。 …

【动态规划】879. 盈利计划

作者推荐 【动态规划】【广度优先搜索】【状态压缩】847 访问所有节点的最短路径 本文涉及知识点 动态规划汇总 LeetCode879. 盈利计划 集团里有 n 名员工&#xff0c;他们可以完成各种各样的工作创造利润。 第 i 种工作会产生 profit[i] 的利润&#xff0c;它要求 group[…

用flinkcdc debezium来捕获数据库的删除内容

我在用flinkcdc把数据从sqlserver写到doris 正常情况下sqlserver有删除数据&#xff0c;doris是能捕获到并很快同步删除的。 但是我现在情况是doris做为数仓&#xff0c;数据写到ods&#xff0c;ods的数据还会通过flink计算后写入dwd层&#xff0c;所以此时ods的数据是删除了…

java SSM自助快递服务平台myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM自助快递服务平台是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

【设计模式】字节三面:请举例阐释访问者模式

今天我们要一起探讨的主题是一种设计模式——访问者模式(Visitor Pattern)。我将从最基础的概念、应用场景&#xff0c;再到实例代码的展示&#xff0c;全方位的为大家剖析访问者模式。而且&#xff0c;我保证&#xff0c;你即使是编程新手&#xff0c;也能理解并开始应用这个设…

Unity3D控制人物移动的多种方法

系列文章目录 unity知识点 文章目录 系列文章目录前言一、人物移动之键盘移动1-1、代码如下1-2、效果 二、人物移动之跟随鼠标点击移动2-1、代码如下2-2、效果 三、人物移动之刚体移动3-1、代码如下3-2、效果 四、人物移动之第一人称控制器移动4-1、代码如下4-2、效果 五、And…

P9232 [蓝桥杯 2023 省 A] 更小的数

[蓝桥杯 2023 省 A] 更小的数 终于本弱一次通关了一道研究生组别的题了[普及/提高−] 一道较为简单的双指针题,但一定有更好的解法. 题目描述 小蓝有一个长度均为 n n n 且仅由数字字符 0 ∼ 9 0 \sim 9 0∼9 组成的字符串&#xff0c;下标从 0 0 0 到 n − 1 n-1 n−1&a…

three.js从入门到精通系列教程052 - 制作立方体添加重影特效

<html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程052 - 制作立方体添加重影特效</title><script src"ThreeJS/three.js"></script><script src"ThreeJS/jquery.js"><…

精品基于Uniapp+springboot智慧校园管理系统App课程选课成绩

《[含文档PPT源码等]精品基于Uniappspringboot智慧校园管理系统App》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 后台框架&#xff1a;springboot、ssm …

动态规划—— 求最长不下降序列LIS【集训笔记】

题目描述 设有由n(1≤n≤200)个整数组成的数列&#xff0c;记为:b(1)、b(2)、……、b(n)&#xff0c;若存在i1<i2<i3<…<ie 且有b(i1)<b(i2)<…<b(ie)则称为长度为e的不下降序列。程序要求&#xff0c;当原数列出之后&#xff0c;求出最长的不下降序列。 …

第16章_网络编程拓展练习(TCP编程,UDP编程)

文章目录 第16章_网络编程拓展练习TCP编程1、学生与老师交互2、查询单词3、拓展&#xff1a;查询单词4、图片上传5、拓展&#xff1a;图片上传6、多个客户端上传文件7、群聊 UDP编程8、群发消息 第16章_网络编程拓展练习 TCP编程 1、学生与老师交互 案例&#xff1a;客户端模…

vue的模板语法-指令-事件绑定-条件渲染

VSCode代码片段生成 我们在前面练习Vue的过程中&#xff0c;有些代码片段是需要经常写的&#xff0c;我们再VSCode中我们可以生成一个代码片段&#xff0c;方便我们快速生成。 VSCode中的代码片段有固定的格式&#xff0c;所以我们一般会借助于一个在线工具来完成。 具体的步…

前端模板字符串的使用

目录 1.说明 2.示例 3.总结 1.说明 模板字符串是用反引号&#xff08;&#xff09;分隔的字面量&#xff0c;允许多行字符串&#xff0c;带有嵌入表达式的字符串插值和一种带标签的模板的特殊结构。 是增强版的字符串&#xff0c;在进行字符串拼接时&#xff0c;可以拼接固…

基本的 Socket 模型

什么是Socket Socket 的中文名叫作插口&#xff0c;咋一看还挺迷惑的。事实上&#xff0c;双方要进行网络通信前&#xff0c;各自得创建一个 Socket&#xff0c;这相当于客户端和服务器都开了一个“口子”&#xff0c;双方读取和发送数据的时候&#xff0c;都通过这个“口子”…

机器学习 | 深入理解并掌握核心概念

在如今数字化时代的浪潮下&#xff0c;机器学习已经成为人工智能领域的璀璨明星。它像一面魔镜&#xff0c;赋予计算机系统学习和改进的能力&#xff0c;让机器能够从海量数据中提取规律、预测未来&#xff0c;甚至做出智能决策。本 专栏 将带您踏上机器学习的奇妙之旅&#xf…