vector的模拟实现

ops/2024/10/21 2:15:12/

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/ops/127155.html

相关文章

重构复杂简单变量之用子类替换类型码

子类替换类型码 是一种用于将类型码替换为子类。当代码使用类型码&#xff08;通常是 int、string 或 enum&#xff09;来表示对象的不同类别&#xff0c;并且这些类别的行为有所不同时&#xff0c;使用子类可以更加清晰地表达这些差异并减少复杂的条件判断。 一、什么时候使用…

音视频入门基础:H.264专题(19)——FFmpeg源码中,获取avcC封装的H.264码流中每个NALU的长度的实现

一、引言 从《音视频入门基础&#xff1a;H.264专题&#xff08;18&#xff09;——AVCDecoderConfigurationRecord简介》中可以知道&#xff0c;avcC跟AnnexB不一样&#xff0c;avcC包装的H.264码流中&#xff0c;每个NALU前面没有起始码。avcC通过在每个NALU前加上NALUnitL…

Whisper 音视频转写

Whisper 音视频转写 API 接口文档 api.py import os import shutil import socket import torch import whisper from moviepy.editor import VideoFileClip import opencc from fastapi import FastAPI, File, UploadFile, Form, HTTPException, Request from fastapi.respons…

vue入门四-pinia

参考&#xff1a;丁丁的哔哩哔哩 vue3中如何设置状态管理 provide/infect 跨级通信1. vue2实现 <!-- index.js --> // 状态集中管理 // 数据实现响应式 // ref reactive--->对象中存储着状态msg,age,counterimport {reactive} from vue const store{state:reactive…

使用verilog设计实现FPGA实现的图像直方图均衡化及其仿真

以下是一个使用Verilog实现图像直方图均衡化的基本框架。 ## 一、图像直方图均衡化原理 1. 首先计算图像的直方图,即统计每个灰度值出现的频率。 2. 然后根据直方图计算累积分布函数(CDF)。 3. 最后根据CDF对每个像素的灰度值进行重新映射,以实现直方图均衡化,增强图像对…

华山论剑之Rust的Trait

华山论剑&#xff0c;群雄荟萃&#xff0c;各显神通。武林中人&#xff0c;各有所长&#xff0c;或剑法飘逸&#xff0c;或掌法刚猛&#xff0c;或轻功绝顶。这就好比Rust中的trait&#xff0c;它定义了一种武功套路&#xff0c;而不同的门派、不同的人&#xff0c;可以将这套武…

在redis创建stream消息队列时报错:ERR unknown command ‘xadd‘

控制台报错内容&#xff1a; 原因&#xff1a; 由于Redis版本过低导致&#xff0c;stream流是5.0版本的新特性&#xff0c;此处为3.2.100的版本会出现这个错误&#xff1b;

React 高级阶段学习计划

React 高级阶段学习计划 目标 深入理解React的渲染机制和性能优化。学会代码分割和懒加载。掌握单元测试和集成测试。学习TypeScript与React的结合。 学习内容 性能优化 React.memo React.memo&#xff1a;用于优化函数组件的性能&#xff0c;避免不必要的重新渲染。示例…