目录

1.vector注意事项

2.vector基本模拟实现

insert迭代器失效

erase迭代器失效场景

erase正确写法

总结:insert/erase不要直接访问pos,必须先更新pos位置再访问,不然就会出现迭代器失效

3.拷贝构造:深拷贝

3.2 内置类型升级

3.3 非法的间接寻址

4.赋值运算符


1.vector注意事项

vector构造函数

default(1):不仅仅允许在模板参数中自己定义空间配置器allocator,还允许在构造函数时自定义传递

fill(2):n个val初始vector,size_type(==size_t)和value_type(第一个模板模板参数)是vector tpyedef的成员类型

range(3):迭代器区间构造

copy(4):拷贝构造


遍历:[]

[]不同于at,at越界抛异常,[]越界assert

返回pos位置数据的引用

vector迭代器类模板不能用类名 ,得用模板类型

void testvector1(){vector<int> v1;vector<int> v2(10, 1);vector<int> v3(v2);for (size_t i = 0; i < v2.size(); ++i){cout << ++v2[i] << " ";//[]返回的数据是对应数据的引用}cout << endl;vector<int>::iterator it = v2.begin();while (it != v2.end()){cout << --(*it) << " ";//迭代器可以修改和遍历,但是注意优先级++it;}cout << endl;for (auto ch : v2){cout<<--ch<<" ";}}

push_back && pop_back

vector只提供了尾插尾删

const value_type& val == const T& val(T可以是任意类型)

void testvector4(){vector<string> s;s.push_back("zhangsan");//隐式类型转换string str1("lisi");s.push_back(str1);s.push_back(string("wangwu"));//匿名结构+隐式类型转换for (auto& e : s)//避免深拷贝{cout << e << " ";}}

insert

vector给的不再是下标位置,而是迭代器

erase

void testvector2(){vector<int> v1(10,2);vector<int>::iterator pos = find(v1.begin(), v1.end(),2);if (pos != v1.end())//没找到返回end{v1.insert(pos, 3);}for (auto ch : v1){cout << ch << " ";}cout << endl;pos = find(v1.begin(), v1.end(), 3);if (pos != v1.end())//没找到返回end{v1.erase(pos);}for (auto ch : v1){cout << ch << " ";}}

sort快排(包含在algorithm头文件中)

传迭代器区间即可排序,默认升序

逆序包头文件<functional>,其中greater是仿函数(大堆降序)

void testvector3(){vector<int> v1;v1.push_back(53);v1.push_back(41);v1.push_back(32);v1.push_back(512);greater<int> gt;less<int> ls;//小堆升序sort(v1.begin(), v1.end(), gt);//sort(v1.begin(), v1.end(),greater<int>());//匿名对象for (auto e : v1){cout << e << " ";e++;}

注意:vector没有重载流提取和流插入

resize和reserve

resize改变size和capacity,reserve只改变capacity

2.vector基本模拟实现

vector重要的成员变量是三个迭代器,迭代器是原生指针

begin是第一个位置,finish是最后一个数据的下一个位置,end_of_storage是最后一个位置

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace std;namespace My_Vector
{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():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){}~vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}size_t capacity() const{return _end_of_storage - _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];}void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){//memcpy(tmp, _start, sizeof(T) * sz);//memcpy是浅拷贝for(size_t i = 0;i < sz;++i)//完成vector的数据深拷贝,防止析构两次{tmp[i] = _start[i];//调用对应T类型的赋值运算符完成深拷贝}delete[] _start;}_start = tmp;_finish = _start + sz;//如果写成+size(),_strat已经改变结果会出错 _end_of_storage = _start + n;}}void resize(size_t n,const T& val = T()){if (n > capacity()){reserve(n);}if (n > size()){while (_finish < _start + n)//初始化填入数据{*_finish = val;++_finish;}}else{_finish = _start + n;}}void push_back(const T& v){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2); }*_finish = v;_finish++;}void pop_back(){assert(_start < _finish);--_finish;}private:iterator _start;iterator _finish;iterator _end_of_storage;};}
}

insert迭代器失效

vector没有find

string的find需求不一样(找一个字符或者子串)

vector,list...的find需求是一样的,于是写成了算法,在algorithm头文件中,只需传迭代器即可,注意左闭右开

找不到返回last,第二个模板参数

错误的insert模拟实现

void insert(iterator pos,const T& x){assert(pos >= _start && pos <= _finish);//=finish 为尾插if (_finish == _end_of_storage){//size_t sz = pos - _start;//解决pos失效问题,不写扩容pos失效出问题reserve(capacity() == 0 ? 4 : capacity() * 2);//pos = _start + sz;//解决pos失效问题,更新pos位置}iterator tail = _finish - 1;while (tail >= pos){*(tail + 1) = *tail;--tail;}*pos = x;_finish++;}

当insert后出现扩容的情况,便会发生迭代器失效

原因:扩容后_start改变(New开辟新空间),旧空间释放,pos迭代器野指针,解应用野指针报错

解决方法:更新insert内部pos位置

第二个问题:pos指向的位置已经不是原来的值,数据发生挪动。insert内部pos修改并不会影响外面实参pos的位置,insert扩容时下次继续对pos位置insert报错

错误程序:在所有的偶数前面插入一个偶数的二倍

void test_vector4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);auto it = v1.begin();while (it != v1.end())//在所有的偶数前面插入一个偶数二倍{if (*it % 2 == 0){v1.insert(it, *it * 2);}++it;}for (auto e : v1){cout << e << " ";}}

程序崩溃,原因在于插入后pos指向新增insert插入的位置,++it == 2,死循环扩容后pos访问野指针

错误解决方法:void insert(iterator& pos,const T& x)

以下情况无法使用iterator&:

头插时v1.insert(v1.begin(),1);原因在于begin函数是传值返回,生成临时变量,具有常性(引用和指针存在权限问题)

解决方法:接收返回值新插入元素的迭代器位置,更新it

     iterator insert(iterator pos,const T& x){assert(pos >= _start && pos <= _finish);//=finish 为尾插if (_finish == _end_of_storage){size_t sz = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + sz;//解决pos失效问题}iterator tail = _finish - 1;while (tail >= pos){*(tail + 1) = *tail;--tail;}*pos = x;_finish++;return pos; }
void test_vector4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);auto it = v1.begin();while (it != v1.end())//在所有的偶数前面插入一个偶数二倍{if (*it % 2 == 0){it = v1.insert(it, *it * 2);++it;//++第一次跳过新插入的值++it;//++第二次跳过判断的值}else{++it;}}for (auto e : v1){cout << e << " ";}}

erase迭代器失效场景

     void erase(iterator pos){assert(pos >= _start && pos < _finish);//开区间iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;}

要求删除所有偶数:程序崩溃

void test_vector3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);vector<int>::iterator it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){v1.erase(it);}++it; }for (auto e : v1){cout << e << " ";}}

要求删除所有偶数:程序正常运行,结果正确

 void test_vector4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int>::iterator it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){v1.erase(it);}++it; }for (auto e : v1){cout << e << " ";}}

运气好

要求删除所有偶数:程序正常运行,结果错误

void test_vector5(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(4);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int>::iterator it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){v1.erase(it);}++it; }for (auto e : v1){cout << e << " ";}}

erase正确写法

要求删除所有偶数,解决方法:带返回值,返回删除元素的下一个位置迭代器

同时,erase接收返回值,更新下标

iterator erase(iterator pos){assert(pos >= _start && pos < _finish);//开区间iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;}void test_vector3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(4);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int>::iterator it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){it = v1.erase(it);}else{++it;}}for (auto e : v1){cout << e << " ";}}

总结:insert/erase不要直接访问pos,必须先更新pos位置再访问,不然就会出现迭代器失效


3.拷贝构造:深拷贝

三个类型都是内置类型(指针),只能完成值拷贝

两种深拷贝写法

注意:不能使用memcpy,vector<T>中T如果是内置类型值拷贝还好,如果还是一个vector或者string,memcpy相当于浅拷贝析构出问题,完成vector内部T数据深拷贝

 vector(const vector<T>& v){_start = new T[v.size()];//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();_end_of_storage = _start + v.size();}vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(v.size());for (const auto& e : v){push_back(e);}}

现代写法需要带参构造函数,我们需要再实现一个迭代器区间构造函数

类模板的成员函数还能增添模板,成员函数中可以使用双重模板

再次定义的模板需要迭代器区间,无法使用iterator的原因是不知道模板类型,对象可能不是vector,写成模板可以用其他容器迭代器区间构造,只要迭代器解应用数据类型匹配即可

template <class InputIterator>         vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while(first != last){   push_back(*first);++first;}}void swap(vector<T>& v){std::swap(_start,v._start);std::swap(_finish,v._finish);std::swap(_end_of_storage,v._end_of_storage);}vector(const vector<T>& v)//v2 = v1:_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){vector<T> tmp(v.begin(), v.end());//调用模板构造函数swap(tmp);}

3.2 内置类型升级

模板的出现让内置类型也有默认构造函数

        int i = 0;int j = int();//0int w = int(10);

3.3 非法的间接寻址

两个构造函数

vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);for (size_t i = 0 ; i < n ; ++i){push_back(val);}}template <class InputIterator>         vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while(first != last){   push_back(*first);++first;}}

传两个参数报错:非法的间接寻址

原因在于实例化时编译器寻找最匹配的构造函数,10,1都是int,和半缺省的size_t和T不是最匹配,而和InputIterator模板最匹配,但并不是迭代器区间,不能解应用报错

解决方法,新增一个int重载即可

 void test_vector7(){//vector<int> v(10, 1);//报错,vector<int> v1(10);vector<int> v2(10, 'a');}

4.赋值运算符

赋值是存在对象,拷贝构造是不存在对象

传参是构造,直接swap现代写法

vector<T>& operator=(vector<T> v)//v2 = v1;{swap(v);return *this;}

C++ 【vector模拟实现】相关推荐

  1. Leetcode402 remove-k-digits贪心+vector模拟栈的思想

    题目 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : 输入: ...

  2. 1390: 队列问题(1)(vector模拟)

    1390: 队列问题(1) Time Limit: 1 Sec Memory Limit: 128 MB Submit: 125 Solved: 50 [Submit][Status][Web Boa ...

  3. 1810: Huffuman树(vector模拟)

    zcmu: 1810: Huffuman树 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 66 Solved: 47 [Submit][Status][ ...

  4. 约瑟夫环问题(vector模拟过程)

    1862: zbj的狼人杀 Time Limit: 1 Sec Memory Limit: 128 MB [Submit][Status][Web Board] Description 这天zbj和小 ...

  5. C++ [STL之vector模拟实现]

    本文已收录至<C++语言和高级数据结构>专栏! 作者:ARMCSKGT STL之vector模拟实现 前言 正文 空间结构 默认成员函数 构造函数 拷贝构造函数 赋值重载 析构函数 关于数 ...

  6. C++知识点 -- vector模拟实现

    C++知识点 – vector模拟实现 文章目录 C++知识点 -- vector模拟实现 一.vector 1.整体结构 2.构造及析构函数 3.capacity和size 4.[]重载 5.res ...

  7. 【C++】vector模拟实现及其应用

    文章目录 vector的介绍 vector的使用及其实现 vector的定义 vector iterator 的使用 vector空间增长问题 vector的增删查改 vector的介绍 vector ...

  8. 【C++】vector模拟实现

    文章目录 1.前提铺垫 2.构造和析构析构模拟 2.1构造相关 2.2 析构相关的 2.3 赋值运算符重载 2.4 接口测试 2.4.1 内置类型测试 2.4.2 自定义类型测试 3.迭代器相关接口模 ...

  9. 【C++ STL】vector模拟实现

    文章目录 前言 vector的模拟实现 一,搭建框架 二,实现构造函数 三,构造的其他方式 传统写法 1.拷贝构造 2. 重载赋值操作符 3. 使用迭代器构造 4. 初始化为N个val的vector ...

最新文章

  1. 'unicodeescape' codec can't decode bytes in position 16-17: malformed \N character escape
  2. 【排错】net::ERR_ABORTED 404
  3. element ui 获取文件的路径_win10使用WinAppDriver实现UI自动化
  4. 查看SecureCRT保存的密码
  5. 巧用 TypeScript Literal Types 模拟枚举类型
  6. 利用python批量修改文件名称
  7. hpsocket java代码_HPSocket介绍与使用
  8. 这个R包自动注释单细胞数据的平均准确率为83%,使用后我的结果出现了点问题|附全代码...
  9. MCMC方法与变分推断
  10. 极速安装JumpServer - 官方文档版
  11. 速更新!流行的开源邮件客户端 Mozilla Thunderbird 91.3修复多个高危缺陷
  12. javamail发送邮件,解决被垃圾邮件问题
  13. Dynamic CRM 2013学习笔记(四)单据编号及插件批量注册工具
  14. nodejs下载安装
  15. 航空公司客户价值分析
  16. android 免root 免流,安卓无需Root一键免流软件合集,具体哪个能用自测
  17. ROSNOTE 发送cmd_vel话题
  18. win10锁屏界面无法更换图片(亲测有效)
  19. tomcat 6x and 7x https配置
  20. 什么是熔断、降级、限流

热门文章

  1. 2-1 第16次课 高项之质量管理
  2. v-show使用三元运算符
  3. idea的pom文件引入依赖,却一直不下载,下载失败
  4. 利用宽乐通信实现PHP网页收发短信
  5. 2023年河北医科大学流行病学考研经验分享
  6. zblog是PHP好还是,「zblog seo」PJBlog和Z-blog哪个好,他们各自的优点是什么,做SEO哪个好...
  7. 详解Gitbook制作精美电子书
  8. 2020最新大厂内部 PHP 高级工程师面试题汇总(一)
  9. 微信小程序之实现一键退出(挂起)小程序以及如何去除 view/navigator 点击后默认阴影效果
  10. 小程序挂服务器,小程序帮微信开挂_服务器x86服务器-中关村在线