C++模拟实现vector

阅读: 评论:0

C++模拟实现vector

C++模拟实现vector

目录

  • 一、定义my_vector类
  • 二、成员函数实现
    • (一)构造函数
    • (二)拷贝构造
    • (三)赋值运算符重载
    • (四)析构函数
    • (五)迭代器
    • (六)容量相关
    • (七)Element Access
      •   []运算符重载
    • (八)修改modify

一、定义my_vector类

  此处标明:以下成员函数都是写在my_list类内部的

#include<iostream>
#include<assert.h>using namespace std;template<class T>
class my_vector
{
public://构造函数//赋值运算符重载//析构函数//迭代器typedef T* iterator;typedef const T* const_iterator;//Capacity//element access//modifyprivate:iterator _start;   //首元素地址iterator _finish;    //最后一个元素下一个位置地址iterator _end_of_storage;    //空间尾地址
};

二、成员函数实现

(一)构造函数

  1、无参构造

	my_vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}

  2、n个value构造

	my_vector(size_t n, const T& val = T()){//开空间_start = new T[n];//赋值size_t i = 0;while (i < n){_start[i] = val;i++;}_finish = _end_of_storage = _start + n;}

  3、迭代器构造
    因为这里的迭代器是一个泛型的迭代器,有可能迭代器内部没有实现减法的功能,所以这里就通过迭代器遍历然后尾插的操作来实现迭代器构造

	template<class InputIterator>my_vector(InputIterator first, InputIterator last){//first和last都是泛型迭代器,并不一定支持相减的操作,所以用迭代器遍历尾插操作构造_start = new T;while (first != last){push_back(first);first++;}}

  构造实例:

	void test(){int arr[5] = {1, 2, 3, 4, 5};my_vector<int> v(arr, arr + 5);}

(二)拷贝构造

	my_vector(const my_vector<T>& v){size_t sz = v.size();size_t cap = v.capacity();//开空间T* tmp = new T[cap];//深拷贝size_t i = 0;while (i < sz){tmp[i] = v[i];i++;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + v.capacity();}

  在将拷贝对象的内容拷贝到构造对象时,因为对象类型可能是自定义类型,所以不能使用memcpy来进行浅拷贝,而是要用循环赋值的方式进行深拷贝

(三)赋值运算符重载

	my_vector<T>& operator=(my_vector<T> v){Swap(v);return *this;}

  首先在接收参数时发生了一次拷贝构造,再将形参与对象本身进行交换,完成了一次深拷贝,函数结束时调用析构将形参析构,这样就完成了一次赋值;

(四)析构函数

	~my_vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}

(五)迭代器

	//迭代器typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator cbeign() const{return _start;}const_iterator cend() const{return _finish;}

(六)容量相关

  1、获取有效元素个数size
    因为 _finish 指向最后一个元素的下一个位置,_start指向首元素位置,所以两个的差值就是有效元素个数;

	size_t size() const{return _finish - _start;}

  2、获取最大有效元素容量capacity
    同理,_end_of_storage指向空间末尾位置,所以与 _start 的差值就是空间的容量;

	size_t capacity() const{return _end_of_storage - _start;}

  3、增加空间总容量reserve
    在增容时,先判断新增的容量是否大于原有空间的容量,如果小于,则不进行增容;
    如果大于则进行以下操作:

		(1)开空间(2)将原有空间内容拷贝到新空间(3)销毁原有空间(4)改变指针指向
	//reservevoid reserve(size_t new_capacity){if (new_capacity > capacity()){size_t sz = size();//开空间T* tmp = new T[new_capacity];//深拷贝size_t i = 0;while (i < sz){tmp[i] = _start[i];i++;}//释放原有空间delete[] _start;//改变指向_start = tmp;_finish = _start + sz;_end_of_storage = _start + new_capacity;}}

  4、改变有效字符个数resize
    改变有效字符个数分为以下几种情况:

(1)当newSize > size时,将新加的空间赋上传入的值;
(2)当newSize > capacity时,reserve增容,再赋值;
(3)当newSize < size时,直接改变_finish指针;
	//resizevoid resize(size_t new_size, const T& val = T()){if (new_size > size()){if (new_size > capacity()){reserve(new_size);}iterator it = end();while (it != _start + new_size){*it = val;it++;}}_finish = _start + new_size;}

(七)Element Access

  []运算符重载

  1、非const修饰的[]运算符重载函数
    在获取index位置的值之前,需要判断边界,看是否越界访问;
    非const修饰的可以访问,也可以修改内容;

	T& operator[](size_t index){//判断边界assert(index < size());return _start[index];}

  2、const修饰的[]运算符重载
    const修饰的可以访问但是不能修改内容

	const T& operator[](size_t index) const{//判断边界assert(index < size());return _start[index];}

(八)修改modify

  1、交换函数Swap

	void Swap(my_vector<T>& v){swap(_start, v._start);swap(_finish, v._finish);swap(_end_of_storage, v._end_of_storage);}

  2、任意位置前插入一个值insert
    插入前首先要判断边界条件和是否需要扩容;

	//任意位置前插入iterator insert(iterator pos, const T& val){//判断边界assert(pos >= begin() && pos <= end());//获取pos的偏移量size_t len = pos - _start;if (_finish == _end_of_storage){size_t new_capacity = (_start == nullptr ? 1 : capacity() * 2);reserve(new_capacity);}iterator it = end();//更新pos的位置,防止增容之后pos失效pos = _start + len;while (it != pos){*it = *(it - 1);it--;}*pos = val;_finish++;return pos;}

    因为传入的位置是迭代器,所以当增容时,会使迭代器失效,那么就必须要更新pos的位置,防止增容之后pos迭代器失效导致出现错误;
    返回值也是一个迭代器,返回的是pos位置的迭代器,指向的就是新加入的元素的位置,这也是防止在插入元素时迭代器失效的问题;
  3、删除任意位置元素erase

	//删除任意位置iterator erase(iterator pos){//判断边界assert(pos >= begin() && pos < end());iterator it = pos + 1;while (it != end()){*(it - 1) = *it;it++;}_finish--;return pos;}

    同插入,删除的返回的也是pos位置的迭代器,指向的就是删除之前下一个元素的位置,这也是防止在插入元素时迭代器失效的问题;
  4、尾插,尾删
    尾插(push_back)、尾删(pop_back)都是inserterase两个函数的复用;

	//尾插void push_back(const T& val){insert(_finish, val);}//尾删void pop_back(){erase(_finish - 1);}

本文发布于:2024-02-02 09:20:51,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170683685242839.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:vector
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23