C++: vector

目录

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.mzph.cn/news/642626.shtml

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

相关文章

simulink限幅模块-Saturation

限幅模块 限幅模块&#xff08;Saturation&#xff09;对输出值施加了上下限约束。当输出值超过上限时&#xff0c;限定于上限值输出&#xff1b;当输出值低于下限时&#xff0c;限定于下限值输出&#xff1b;在上下限之间时&#xff0c;保持原输出。Saturation模块默认包含一…

网络安全--防御保护02

第二天重要的一个点是区域这个概念 防火墙的主要职责在于控制和防护---安全策略---防火墙可以根据安全策略来抓取流量之后做出对应的动作 防火墙的分类&#xff1a; 单一主机防火墙&#xff1a;专门有设备作为防火墙 路由集成&#xff1a;核心设备&#xff0c;可流量转发 分…

为什么单片机不能直接驱动继电器和电磁阀?

为什么单片机不能直接驱动继电器和电磁阀&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&…

vue3源码(一)搭建开发环境

Monorepo:是管理项目代码的一个方式&#xff0c;指在一个项目仓库(repo)中管理多个模块/包(package) vue3源码采用Monorepo管理项目 vue3项目架构 搭建Monorepo环境 1.全局安装pnpm npm install pnpm -g # 全局安装pnpm pnpm init -y # 初始化配置文件创建.npmrc文件&#x…

Docker基础语法

目录 一.docker安装 二.docker基础名词 三.docker基础命令 四.命令别名 五.数据卷 六.挂载本地目录或文件 七.Docker镜像 八.网络 一.docker安装 1.安装yum工具 yum install -y yum-utils device-mapper-persistent-data lvm2 2.安装 docker yum源 yum-config-manag…

EXECL 单元格字符串链接 CONCAT :应用:将一行数据转为json

源&#xff1a; 目标 函数表示 CONCAT("data", CHAR(10), "{", CHAR(10), " ", "ulAlarmId : ", A5, CHAR(10), " ", "ulAlarmLevel : ", D5, CHAR(10)," ", "bBo…

JavaEE-微服务-Vuex

Vuex 2.1 什么是Vuex Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 Vuex在组件之间共享数据。 2.2 使用 vue cli 构建项目 2.3 入门案例 2.3.1 定义数据 export default new Vuex.Store({state: { // 状态区域&#xff08;定义变量区域&#xff09;user: ,toke…

Ubuntu Desktop 隐藏 / 显示文件和文件夹

Ubuntu Desktop 隐藏 / 显示文件和文件夹 1. GUI hot key2. Show hidden and backup filesReferences 1. GUI hot key Ctrl H: 隐藏 / 显示文件和文件夹 2. Show hidden and backup files Edit -> Preferences -> Views References [1] Yongqiang Cheng, https://yo…

梳理Langchain-Chatchat知识库API接口

一.Langchain-Chatchat 知识库管理 1.Langchain-Chatchat 对话和知识库管理界面 Langchain-Chatchat v0.28 完整的界面截图&#xff0c;如下所示&#xff1a; 2.知识库中源文件和向量库 知识库 test 中源文件和向量库的位置&#xff0c;如下所示&#xff1a; 3.知识库表结构 k…

一夜暴增200城,智驾开城秘诀在哪?小鹏、理想、大疆等各有不同

作者 |Marshall 编辑 |祥威 一夜过后&#xff0c;城市NOA可用范围突然增至两百多城市&#xff0c;这是最近小鹏的智驾给大家的印象。 我们曾在「特斯拉、小鹏开路&#xff0c;城市NOA距好用还有几年&#xff1f;」一文中&#xff0c;探讨了城市NOA落地过程中所面临的地图问题…

vue3-组件基础

什么是组件 组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行处理。在实际应用中&#xff0c;组件常常被组织成层层嵌套的树状结构。 定义一个组件 我们一般会将 Vue 组件定义在一个单独的 .vue 文件中&#xff0c;这被叫做单文件组件 (简称…

TypeScript 实用技巧(中)

十四、向类型添加特殊值 原文&#xff1a;exploringjs.com/tackling-ts/ch_special-values.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 14.1 在带内添加特殊值 14.1.1 向类型添加 null 或 undefined 14.1.2 向类型添加符号 14.2 在带外添加特殊值 14.2…

[亲测有效]CentOS7下安装mysql5.7

前言 近期项目需要搭配mysql一起存储相关数据&#xff0c;但对mysql的版本有要求&#xff0c;于是在服务器搭建了mysql5.7&#xff0c;顺便记录一下搭建步骤和踩坑解决步骤。 目录 前言 一、清除旧安装包 二、安装YUM 三、使用yum命令即可完成安装 四、重新设置密码 五、…

文心一言 v.s. ChatGPT:多角度对比测评“追赶者”能否超越?

ChatGPT自发布以来就引发了关注热潮&#xff0c;如今国内大模型的发展也是如火如荼、百花齐放&#xff1a;比如百度的文心一言、阿里的通义千问、讯飞的星火大模型等等&#xff0c;那么作为后起之秀的国内大模型与ChatGPT相比哪个更好用呢&#xff1f;“追赶者”能否实现超越&a…

使用Unity创建VisionPro应用

1、下载特定Unity版本 Unity账号需要是Pro账号,普通账号不行,目前只支持这1个Unity版本,不要下载任何其它版本:unityhub://2022.3.11f1/d00248457e15) 其它条件:使用Mac电脑M系列芯片,XCode15 Beta2及以上 参考资料: 苹果官网:苹果官网 Unity官网:Unity官网 官方教程…

Network:use `--host` to expose

前言&#xff1a; 最近开始学习使用vite创建项目&#xff0c;但是 vite 启动后提示&#xff1a;Network:use --host to expose&#xff0c;从而导致在同一个局域网内的其他人也无法访问到我本地的项目。 导致原因&#xff1a;通过官方文档了解到不显示地址是因为IP没有做配置&a…

浏览器无网

目录 1.运行网络诊断&#xff0c;确认原因 原因A.远程计算机或设备将不接受连接(该设备或资源(Web 代理)未设置为接受端口“7890”上的连接 原因B.DNS服务器未响应 场景A.其他的浏览器可以打开网页&#xff0c;自带的Edge却不行 方法A&#xff1a;关闭代理 Google自带翻译…

【江科大】STM32:中断系统(理论)

文章目录 中断系统为什么要使用中断中断优先级中断嵌套STM32的中断系统如何管理这些中断NVIC的结构![请添加图片描述](https://img-blog.csdnimg.cn/c77b038fd63a4ddfbcd3b86f6dfe596b.png) 优先级窗口看门狗&#xff08;WWDG&#xff09;&#xff1a;外部中断模块的特性&#…

前后端分离项目中实现图形验证码

图形验证码在我们的日常生活中时经常用到的&#xff0c;一般用于用户的登录、注册等。 图形验证码在互联网应用中的作用是提高安全性、防止滥用和保护用户隐私。它是一种简单而有效的人机验证技术&#xff0c;帮助保护系统和用户免受自动化攻击的影响。 本次我们通过spring b…

损失函数是指什么

损失函数&#xff08;Loss Function&#xff09;是用来衡量模型预测输出与实际目标之间差异的函数。在机器学习和深度学习中&#xff0c;损失函数是模型训练的关键部分。其目标是通过最小化损失函数来使模型的预测尽可能接近实际的标签或目标值。 在监督学习中&#xff0c;模型…