C++知识点 -- vector模拟实现
C++知识点 – vector模拟实现
文章目录
- C++知识点 -- vector模拟实现
- 一、vector
- 1.整体结构
- 2.构造及析构函数
- 3.capacity和size
- 4.[]重载
- 5.reserve
- 5.push_back和pop_back
- 6.迭代器
- 7.insert
- 8.erase
- 9.拷贝构造
- 10.赋值重载
- 11.resize
- 12.front和back
一、vector
1.整体结构
代码如下:
namespace lmx
{template<class T>class vector{public:typedef T* iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;};
}
2.构造及析构函数
代码如下:
vector(): _start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}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);}}~vector(){delete[] _strat;_start = _finish = _end_of_storage = nullptr;}
3.capacity和size
代码如下:
size_t capacity() const{return _end_of_storage - _start;}size_t size() const{return _finish - _start;}
4.[]重载
代码如下:
T operator[](size_t pos) const{assert(pos < size());return _start[pos];}
5.reserve
代码如下:
void reserve(size_t n){if (n > capacity()){size_t sz = size();//先保存size(),后面开新空间后size会更新T* tmp = new T[n];if (_start){memccpy(tmp, _start, sizeof(T) * sz);delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}
这种写法是有问题的,因为vector中还有可能存自定义类型,如果使用memcpy来拷贝数据,就会发生浅拷贝。
直接赋值,自定义类型会调用赋值重载,就是深拷贝了。
void reserve(size_t n){if (n > capacity()){size_t sz = size();//先保存size(),后面开新空间后size会更新T* tmp = new T[n];if (_start){//memccpy(tmp, _start, sizeof(T) * sz);for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}
5.push_back和pop_back
代码如下:
void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;_finish++;}
如果形参的引用前不加const,那么以下的情况会报错:
由于string是单参形式的构造函数,会发生隐式类型转换,将常量字符串"xxxx"转为string类型,生成一个string的临时对象,而临时对象具有常性,传参时,形参的引用前不加const,就是权限放大,导致报错。
void pop_back(){assert(_finish > _start);_finish--;}
6.迭代器
代码如下:
iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}
7.insert
代码如下:
void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;}
这种写法会导致迭代器失效,具体情况如下:
void TestVector2(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);//v1.push_back(5);for (auto a : v1){cout << a << ' ';}cout << endl;auto pos = find(v1.begin(), v1.end(), 3);if (pos != v1.end()){v1.insert(pos, 25);}for (auto a : v1){cout << a << ' ';}cout << endl;}
在上面的测试代码中,如果只插入4个数据,此时容量是满的,在insert时就会扩容,开辟一块新空间,然后挪动数据,但是pos是一个迭代器,依然指向原空间的某个地址,此时原空间被释放了,pos就变成了野指针,这就叫做迭代器失效。
改进:在insert中扩容时,也要更新pos;
iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;//返回pos}
8.erase
代码如下:
iterator erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;//返回该位置的迭代器}
9.拷贝构造
代码如下:
vector(vector<T>& v){_start = new T[v.szie()];memcpy(_strat, v._start, sizeof(T) * v.size());_finish = _start + v.size();_end_of_storage = _start + v.size();}
vector的拷贝构造不是使用memcpy来进行数据迁移,因为memcpy是浅拷贝,vector中有可能会存自定义类型,浅拷贝是不行的,因此,需要逐个数据进行迁移:
vector(const vector<T>& v){_start = new T[v.szie()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.size();}
也可以复用push_back:
vector(const vector<T>& v): _start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(v.size());for (auto e : v){push_back(e);}}
现代写法:
//先写一个迭代器区间的构造函数类模板//方便使用其他容器的迭代器构造template<class InputIteratort>vector(InputIteratort first, InputIteratort last)//迭代器区间的构造函数: _start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while (first != last){push_back(*first);first++;}}void swap(vector<T>& v){::swap(_start, v._start);::swap(_finish, v._finish);::swap(_end_of_storage, v._end_of_storage);}vector(const vector<T>& v) //: _start(nullptr), _finish(nullptr), _end_of_storage(nullptr){vector<T> tmp(v.begin(), v.end());swap(tmp);}
10.赋值重载
代码如下:
vector<T> operator=(vector<T> v){swap(v);return *this;}
使用传值传参,v是形参的临时拷贝, 然后直接交换this和v,this就有了值,v出了作用域也会自动析构。
11.resize
代码如下:
void resize(size_t n, const T& val = T())//T()是T类型的匿名对象{if (n > capacity()){reserve(n);}if (n > size()){while (_finish < _start + n){*_finish = val;_finish++;}}else{_finish = _start + n;}}
12.front和back
代码如下:
T& front(){assert(size() > 0);return *_start;}T& bcak(){assert(size() > 0);return *(_finish - 1);}
C++知识点 -- vector模拟实现相关推荐
- Leetcode402 remove-k-digits贪心+vector模拟栈的思想
题目 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : 输入: ...
- 1390: 队列问题(1)(vector模拟)
1390: 队列问题(1) Time Limit: 1 Sec Memory Limit: 128 MB Submit: 125 Solved: 50 [Submit][Status][Web Boa ...
- 1810: Huffuman树(vector模拟)
zcmu: 1810: Huffuman树 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 66 Solved: 47 [Submit][Status][ ...
- 约瑟夫环问题(vector模拟过程)
1862: zbj的狼人杀 Time Limit: 1 Sec Memory Limit: 128 MB [Submit][Status][Web Board] Description 这天zbj和小 ...
- C++ [STL之vector模拟实现]
本文已收录至<C++语言和高级数据结构>专栏! 作者:ARMCSKGT STL之vector模拟实现 前言 正文 空间结构 默认成员函数 构造函数 拷贝构造函数 赋值重载 析构函数 关于数 ...
- 1147 Heaps (30 分)【难度: 一般 / 知识点: 堆 模拟 】
https://pintia.cn/problem-sets/994805342720868352/problems/994805342821531648 直接按照堆模拟即可,如果对于每一个根来说,它 ...
- C++ 【vector模拟实现】
目录 1.vector注意事项 2.vector基本模拟实现 insert迭代器失效 erase迭代器失效场景 erase正确写法 总结:insert/erase不要直接访问pos,必须先更新pos位 ...
- 【C++】vector模拟实现及其应用
文章目录 vector的介绍 vector的使用及其实现 vector的定义 vector iterator 的使用 vector空间增长问题 vector的增删查改 vector的介绍 vector ...
- 【C++】vector模拟实现
文章目录 1.前提铺垫 2.构造和析构析构模拟 2.1构造相关 2.2 析构相关的 2.3 赋值运算符重载 2.4 接口测试 2.4.1 内置类型测试 2.4.2 自定义类型测试 3.迭代器相关接口模 ...
最新文章
- 写缓冲器 + 无效队列,优化MESI协议的性能
- 【bzoj3524】Couriers——主席树
- [Swift]LeetCode522. 最长特殊序列 II | Longest Uncommon Subsequence II
- 苹果ipa签名工具免越狱下载_苹果iphone免越狱使用iTunes 一键下载旧版本app
- map和hasmap的区别
- oracle中变量前加冒号_ORACLE 变量的定义和使用
- 常见MIME类型例表
- apache 版本_Apache官宣!ShardingSphere首个Apache版本发布
- sql语句:CASE WHEN END 的用法
- MindMaster Pro 7.2中文版 — 亿图思维导图
- WPF中直接打开网页方法总结
- 龙之谷手游微信连接授权服务器失败,龙之谷手游ios微信授权失败怎么办_龙之谷手游ios微信授权失败解决办法-66街机网...
- 损失 18 万,获刑 7 年,又又又是程序员删库!
- phoenix查不到数据_Phoenix查询测试经验总结
- Chrome开发者工具不完全指南:(三、性能篇)
- 轩小陌的Python笔记-Pandas时间序列与日期
- mysql自动备份快结束很卡_mysql备份慢以及自动重启问题——调整NUMA
- 盘点适合入门学习的C/C++开源项目
- android刷机刷系统
- 换三张麻将源代码php,理论先行:麻将换三张攻略大全