vector的模拟实现

embedded/2024/10/21 0:45:15/

1.迭代器失效

在上一篇中因为插入导致的扩容,扩容则pos指向的是之前的空间,导致了野指针的出现,没有扩容,使pos的位置意义改变,由于数据挪动,pos不再指向原来的位置,认为上面俩种迭代器失效。(vs有强制检查,如果出现上面情况会直接报错)

可以通过修正pos来保证迭代器的有效性。

先尾插4个数据,这里发if和else就是完成修正的,如果是偶数就删除,不是就下一个,如果是是删除再下一个就会出现问题,因为数据会挪动,就是说数据向前一步,it向后一步,则it就会跳过一个数据。

实现版本:

	void test_vector3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//v.push_back(5);print_container(v);// 删除所有的偶数auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){v.erase(it);}else{++it;}}print_container(v);}

std版本:

std的vector,则v.erase()就是std的删除了,不是实现的,而std的erase会把删除位置的下一个位置传回来,所以要接收。

	void test_vector3(){std::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//v.push_back(5);print_container(v);// 删除所有的偶数auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){it=v.erase(it);}else{++it;}}print_container(v);}

 

2.实现resize

resize的实现需要讨论区间,输入的n小于原大小,或者是介于大小和容量之间,最后是大于容量。if判断,如果小于size则就减成n个大小,else就大于等于的情况,等于不用变,大于就扩大并且把第二个参数填到n个,这里T val=T()而不是等于0是因为要兼容多个类型,然后不是每个类型都可以用0初始化,T()是匿名对象,生成一个临时变量来初始化,每个类型都会走对应的初始化,内置类型就一般会赋值为0,而类就会走自己的构造。

 

		void resize(size_t n, T val = T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}}

1.匿名对象

 

2.默认构造:

defalut可以构造一个成员变量都为默认值的类,像上面一样,int会变为0,需要注意的是,编译器生成一个默认构造的前提是没有然后一个构造函数,而拷贝构造出现,编译器也不会生成默认构造函数,因为拷贝构造也是构造函数。

	//vector()//	/*: _start(nullptr)//	,_finish(nullptr)//	,_end_of_storage(nullptr)*///{}C++11 前置生成默认构造vector() = default;

3.拷贝构造

通过范围for,把v的每一个值都尾插到生成的类指向的空间上。 

		vector(const vector<T>& v){reserve(v.size());for (auto& e : v){push_back(e);}}
	void push_back(const T& x){// 扩容if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}

 

4.赋值运算符重载 

注释的代码虽然跟拷贝构造大差不差,但区别是拷贝构造是一个已经存在的对象去初始化另一个还没有初始化的对象,而赋值运算符重载是俩个已经存在的对象,没有注释则是通过std库的swap来实现,效率比模板swap的三次深拷贝快(若存在指向资源)。

// v1 = v3
/*vector<T>& operator=(const vector<T>& v)
{if (this != &v){clear();reserve(v.size());for (auto& e : v){push_back(e);}}return *this;
}*/void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}// v1 = v3
//vector& operator=(vector v)
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}

 

5. 类模板的构造函数

		// 类模板的成员函数,还可以继续是函数模版template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}
	void test_vector6(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(4);vector<int> v2(v1.begin(), v1.begin() + 3);print_container(v1);print_container(v2);list<int> lt;lt.push_back(10);lt.push_back(10);lt.push_back(10);lt.push_back(10);vector<int> v3(lt.begin(), lt.end());print_container(lt);print_container(v2);vector<string> v4(10, "1111111");print_container(v4);vector<int> v5(10);print_container(v5);//vector<int> v6(10u, 1);//print_container(v6);vector<int> v7(10, 1);print_container(v7);}

可以用list的来初始vector,这就是模板的优势,可以兼容多个,灵活性高。 

 

优势

  • 灵活性:由于使用了模板,您可以从不同类型的容器或自定义的迭代器创建 vector,提高了代码的重用性。
  • 适应性:可以方便地适应不同数据源的输入,支持 STL 中的所有容器和任何自定义的迭代器类型。

 

 

vector<int> v7(10, 1);print_container(v7);

 运行测试6时出现了下面的错误,是因为有俩个选择,但是肯定是会去最合适的,那这样第一个就比较合适,俩个InputIterator都是int,编译器默认整数为int,所以会选择上一个,但是选了上一个,就会错误,因为10为first,1为finish,会一直循环,解决方法就是在10后面加个u表示这个10是size_t类型的。编译器则是写了很多个这种函数,为的就是有更多选择,让其能找到最合适的,从而不会出现错误。

 

6.memcpy浅拷贝

可以看到在没有扩容是,尾插字符串是可以的,但扩容是就出现乱码了,是因为随机数对应值刚好为这些,memcpy是一个一个字节拷贝的是浅拷贝,而v是有指向的内部资源的,所以会有俩个指向同一片区域,而当另一个析构是,剩下一个指向的就是没有权限的空间了,所以原空间的四个就没有了,只剩下第五个还在,把浅拷贝改进成深拷贝就行了,用string的赋值运算符重载来实现,这个是深拷贝的方法。

	void test_vector7(){vector<string> v;v.push_back("11111111111111111111");v.push_back("11111111111111111111");v.push_back("11111111111111111111");v.push_back("11111111111111111111");print_container(v);v.push_back("11111111111111111111");print_container(v);}

string的赋值运算符重载: 

string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;

 

 

 

 

 

7.总代码

vector.h

#pragma once
#include<assert.h>
#include<list>
#include<string>
#include<vector>
#include<iostream>using namespace std;namespace zym
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;//vector()//	/*: _start(nullptr)//	,_finish(nullptr)//	,_end_of_storage(nullptr)*///{}C++11 前置生成默认构造vector() = default;vector(const vector<T>& v){reserve(v.size());for (auto& e : v){push_back(e);}}// 类模板的成员函数,还可以继续是函数模版template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}/*vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}*/void clear(){_finish = _start;}// v1 = v3/*vector<T>& operator=(const vector<T>& v){if (this != &v){clear();reserve(v.size());for (auto& e : v){push_back(e);}}return *this;}*/void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}// v1 = v3//vector& operator=(vector v)vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}void reserve(size_t n){if (n > capacity()){size_t old_size = size();T* tmp = new T[n];memcpy(tmp, _start, old_size * sizeof(T));/*for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}*/delete[] _start;_start = tmp;_finish = tmp + old_size;_end_of_storage = tmp + n;}}void resize(size_t n, T val = T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}}size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;}bool empty() const{return _start == _finish;}void push_back(const T& x){// 扩容if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}void pop_back(){assert(!empty());--_finish;}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;}void erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it != end()){*(it - 1) = *it;++it;}--_finish;}T& operator[](size_t i){assert(i < size());return _start[i];}const T& operator[](size_t i) const{assert(i < size());return _start[i];}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};/*void print_vector(const vector<int>& v){vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;}*/template<class T>void print_vector(const vector<T>& v){// 规定,没有实例化的类模板里面取东西,编译器不能区分这里const_iterator// 是类型还是静态成员变量//typename vector<T>::const_iterator it = v.begin();auto it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;}template<class Container>void print_container(const Container& v){/*auto it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;*/for (auto e : v){cout << e << " ";}cout << endl;}void test_vector3(){std::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//v.push_back(5);print_container(v);// 删除所有的偶数auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){it=v.erase(it);}else{++it;}}print_container(v);}void test_vector4(){int i = int();int j = int(1);int k(2);vector<int> v;v.resize(10, 1);v.reserve(20);print_container(v);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(15, 2);print_container(v);v.resize(25, 3);print_container(v);v.resize(5);print_container(v);}void test_vector6(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(4);vector<int> v2(v1.begin(), v1.begin() + 3);print_container(v1);print_container(v2);list<int> lt;lt.push_back(10);lt.push_back(10);lt.push_back(10);lt.push_back(10);vector<int> v3(lt.begin(), lt.end());print_container(lt);print_container(v2);vector<string> v4(10, "1111111");print_container(v4);vector<int> v5(10);print_container(v5);//vector<int> v6(10u, 1);//print_container(v6);vector<int> v7(10u, 1);print_container(v7);}void test_vector7(){vector<string> v;v.push_back("11111111111111111111");v.push_back("11111111111111111111");v.push_back("11111111111111111111");v.push_back("11111111111111111111");print_container(v);v.push_back("11111111111111111111");print_container(v);}
}

test.cpp 


#include"vector.h"int main()
{zym::test_vector7();
}


http://www.ppmy.cn/embedded/129138.html

相关文章

LeetCode两数相加

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …

Gin框架操作指南08:日志与安全

官方文档地址&#xff08;中文&#xff09;&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;本教程采用工作区机制&#xff0c;所以一个项目下载了Gin框架&#xff0c;其余项目就无需重复下载&#xff0c;想了解的读者可阅读第一节&#xff1a;Gin操作指南&#…

MongoDB聚合管道(Aggregation Pipeline)

聚合管道&#xff08;Aggregation Pipeline&#xff09;是MongoDB中用于对数据进行处理和分析的一种强大机制。它由一系列的阶段&#xff08;Stage&#xff09;组成&#xff0c;每个阶段对输入的数据进行一种特定的操作&#xff0c;然后将结果传递给下一个阶段&#xff0c;就像…

Linux安装 php5.6

Linux安装 php5.6.30 下载-解压-配置-安装 下载到 /usr/local wget http://am1.php.net/distributions/php-5.6.30.tar.gztar -zxvf php-5.6.30.tar.gz cd php-5.6.30#编译配置 ./configure --prefix/usr/local/php --with-curl/usr/local/curl --with-freetype-dir --wit…

【算法日记】力扣239 滑动窗口最大值

题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a;nums [1,3,-1,-3,5,3,6,…

已解决:ModuleNotFoundError: No module named ‘pip‘

[已解决] ModuleNotFoundError: No module named ‘pip‘ 文章目录 写在前面问题描述报错原因分析 解决思路解决办法1. 手动安装或升级 pip2. 使用 get-pip.py 脚本3. 检查环境变量配置4. 重新安装 Python 并确保添加到 PATH5. 在虚拟环境中安装 pip6. 使用 conda 安装 pip&…

持续科技创新 高德亮相2024中国测绘地理信息科技年会

图为博览会期间, 自然资源部党组成员、副部长刘国洪前往高德企业展台参观。 10月15日&#xff0c;2024中国测绘地理信息科学技术年会暨中国测绘地理信息技术装备博览会在郑州召开。作为国内领先的地图厂商&#xff0c;高德地图凭借高精度高动态导航地图技术应用受邀参会。 本…

Windows电脑桌面如何弄个好用的提醒备忘录?

在这个充满挑战的时代&#xff0c;每个人都渴望成为更好的自己。然而&#xff0c;随着生活节奏的加快&#xff0c;我们时常发现自己陷入了各种琐事之中&#xff0c;难以脱身。为了不让重要的事情被遗漏&#xff0c;一款好的提醒备忘录工具就显得尤为关键。那么&#xff0c;Wind…