2024/4/19学习笔记 vector模拟实现(2)

news/2024/12/22 14:30:55/

本次学习重点

1.迭代器区间构造和size_t n 构造

2.string扩容问题

3.erase的缺陷

1.迭代器区间构造和size_t n 构造

vector支持用一段迭代器区间构造,也可以支持任意类型的迭代器区间,所以要写成函数模板

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

vector还可以利用给定的初始值进行初始化构造,为了方便使用各种类型的初始值,这里要使用匿名对象临时构造初始值。

如果是内置类型的话,也需要走构造函数吗?是的,内置命令也是要通过构造函数进行初始化的,只是平常使用时重载了一些运算符,用起来会更加方便。

vector(size_t n, const T& val = T())
{reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}
}

但这两个函数在进行调用时会出现问题,编译器无法对要调用哪一个函数进行匹配,区分不出到底是迭代器还是无符号整数,如果要同时满足的话,就要在size_t 构造时加上u标识无符号整数。 

2.string扩容问题

vector可以构造string类的动态数组,当我们需要对这个数组进行扩容时就需要考虑一下值拷贝的问题。

模拟实现vector的push_back时,采用的是基于原理的开辟新空间,将旧空间的内容拷贝到新空间去(memcpy),看上去好像并没有什么问题,但如果是元素是string类的话就犯大错了,构造时并不会出现什么,但析构时会报错。

string类底层是字符串类型,我们所构造的string类型是将一系列成员变量对字符串进行映射,而字符串存放的位置在静态区,扩容后,新空间的成员也对静态区的字符串建立了映射,当我们释放掉旧空间时释放的是成员指向的内容而非成员本身,当程序结束析构时就会对同一块空间进行多次释放。

解决方法是利用赋值的特性给旧数据拷贝一份新的数据,放在新的空间里。

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

3.erase的缺陷

vector的erase是删除对应下标的元素,但它并不是万能的。

举个例子,如果需要删除数组里对应的偶数,erase底层走的是挪动元素进行删除,下面的可能不会有什么问题,但当重复的偶数出现时,就会删不干净。

原因是因为迭代器失效了。在第一次删除后,我们挪动数据,挪完后此时迭代器指向的内容并不会进行判断就直接移动到下一个去。

而且还会出现越界问题,要谨慎使用。


http://www.ppmy.cn/news/1434569.html

相关文章

VUE-配置-流程

VUE-配置-流程 ---1---.安装 NVM: ---2---.用NVM:安装node.js &#xff1a; 修改源&#xff1a; nvm root 命令&#xff0c;可以查看nvm的安装根路径在那个文件夹 root地址&#xff0c;找到setting.txt文件并打开 复制粘贴以下代码&#xff0c; 保存完成nvm源修改&#xff…

MATLAB初学者入门(8)—— 动态规划

动态规划是一种数学方法&#xff0c;用于解决具有递归结构的决策问题&#xff0c;特别是那些涉及顺序决策的问题。在MATLAB中实现动态规划&#xff0c;可以通过定义状态变量、决策变量、状态转移方程以及目标函数来完成。以下是具体的案例分析。 案例分析&#xff1a;项目资源…

Oracle使用内部包自定义创建表空间和用户

如果之前有类似的表空间,可以使用dbms自动生成对应的表空间和数据文件 select dbms_metadata.get_ddl(TABLESPACE,ts.tablespace_name) from dba_tablespaces ts; 可以使用类似的 SQL> set echo off SQL> spool /data/logs/create_tablespace.log SQL> select dbms…

SqL--DCL数据控制语言

文章目录 数据控制语言用户角色 赋权收权删除用户自定义角色 数据控制语言 用户 用户&#xff1a;用来登录数据库的账号 需要有权限的用户或者管理员用户system 创建用户&#xff1a; 语法&#xff1a; CREATE USER 用户名 IDENTIFIED BY 密码;注意&#xff1a;1.此时的用户…

浅析Java中的LinkedList和ArrayList特点和底层

本期经验 LinkedList适合于删除和插入元素的操作&#xff0c;对首元素和尾元素的删除和修改插入极好&#xff0c;ArrayList适合于元素的修改和查询。 LinkedList LinkedList的底层使用双向链表来写&#xff0c;这导致其每次查询和修改元素都必须从首元素开始以此往下找&…

.NET 基于Socket中转WebSocket

前言 针对IOS App Proxy Server无法直连WebSocket&#xff0c;建立 Socket中转端。 WebSocket 端&#xff1a; WebSocket 端用于实现实时通信功能。 WebSocket 端通过 WebSocket 协议与中转端通信&#xff0c;中转端可以通过 WebSocket 或其他传输协议与 WebSocket 端建立连…

Pytorch或Tensorflow 深度学习库安装 (简易版)

Tensorflow 2.X安装 0、 pytorch 支持 conda虚拟环境 cuda 和 cudnn1、创建conda环境2、测试GPU是否可用3、在机器上安装cuda 和 cudnnCUDA 安装cudnn 安装 0、 pytorch 支持 conda虚拟环境 cuda 和 cudnn 如果只用pytorch&#xff0c; 只需在虚拟环境安装cuda 和 cudnn即可&am…

JavaScript 模块导出示例

JavaScript 模块导出示例说明 在 JavaScript 中&#xff0c;我们可以通过 export 关键字将模块中的功能导出&#xff0c;以供其他模块使用。导出可以是单个默认值&#xff0c;也可以是多个命名值。本文将分别介绍导出单个值和导出多个值的示例说明。 导出单个值 当模块中只有…