C++实现vector

目录

前言

1.成员变量

2.成员函数

2.1构造函数

2.2析构函数

2.3begin,end

2.4获取size和capacity

2.5函数重载【】

2.6扩容reserve

2.7resize

2.8insert

2.9删除

2.10尾插、尾删

3.0拷贝构造函数

3.1赋值运算符重载


前言

自主实现C++中vector大部分的功能可以使我们更好的理解并使用vector。本篇我们只会实现最常用的,因为我们的目的不是要超越或则弄一个一模一样的,而是去理解。

1.成员变量

我们先来看看vector中的成员变量,在这里我们定义了3个成员变量,并为了安全性的考量给它们的权限定位private。我们知道vector是顺序表的意思,而顺序表的底层是由数组来实现的,所以我们第一个变量_start的意思是数组的头部位置,大家可能会很疑惑,数组的头部位置不是应该用指针吗,这里为什么用迭代器类型呢?

其实这里没啥门道,我们得知道迭代器的本质类型其实是由其它类型的typedef过来的,像这里我们这样用是因为我们typedef的就是指针类型。

T是我们类模板的类型,这样可以保证我们的vector不受类型限制,而T*不就是我们的指针类型吗,这里typedef了两个,第二个我们是用const修饰的,这是因为会有将vector定义成const属性的情况。

知道了这些之后我们就好理解了,_start指向开头,_finish指向结尾,_endofstorage指向空间边界。

2.成员函数

2.1构造函数

因为我们的构造不涉及深拷贝以及动态开辟空间,而且我们的成员变量都已经附上初始值了,所以单纯的无参构造就不需要写任何东西了。

2.2析构函数

我们的析构函数也很简单,我们只需要delete掉_start,然后将这3个变量赋为空就行了。

2.3begin,end

begin和end我们要写两种的原因跟上面一样,是为了应对常属性的情况。

2.4获取size和capacity

这两个实现也很简单,光看代码就能理解。

2.5函数重载【】

这个操作也很简单,我们只需要断言一下pos是否超出有效范围,正常的话就返回那个值就可以了。

2.6扩容reserve

reserve是我们的扩容操作,所以我们先看看是否大于我们的空间,大就扩容,小就不操作,

我们先定义一个old_size来记录我们的原先数组的有效元素个数,然后再定义一个tmp来充当中转站,然后用for循环直接将_start里的每一个元素赋值给tmp,然后就可以将原先的数组空间清楚了,然后我们再把_start跟tmp相等,_finish、_endofstorage调成对应的就可以了。出这个函数我们的tmp指针是会自动销毁的,但空间是动态开辟的所以不需要担心泄露或野指针的问题。

2.7resize

resize可以控制我们有效元素的个数,如果扩大的个数超过空间大小还会进行扩容操作,这里唯一需要解释一下的就是第二个参数了,第二个参数的设计很巧妙,我们知道第二个参数是为了应付增加有效元素个数准备的,比如这个参数你传的是0,那么就用0来填补数组,所以问题也就来了,我们除了基本类型以外还有可能是类的类型,而这两种类型给的缺省值方式是不一样的,那要怎么做到一个统一呢?

C++提供了一种方法,就是创建匿名对象,C++是支持int a = int(),这种写法的,所以我们就可以利用这一点将基本类型和引用类型的差异给解决。

2.8insert

//插入insert
		void insert(iterator pos, const T& val)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			//扩容
			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * capacity());
				//刷新pos
				pos = _start + len;
			}

			//插入数据
			iterator it = _finish - 1;
			while (pos <= it)
			{
				*(it + 1) = *it;
				it--;
			}
			*pos = val;
			_finish++;
		}

插入操作也很简单,我们第一步要进行断言操作,你总不能随便传一个下标值吧,然后我们要判断一下是否需要扩容,扩容阶段结束后就到了插入数据的时候了,整个插入过程其实非常朴素,没有什么难点。

2.9删除

删除操作就更简单了,还是先断言,但我们要注意,这次pos不能等于_finish,因为插入操作的情况下,我们的pos如果是_finish可以理解为它是进行尾插,但是删除总不能把'\0'给删除吧。只要理解了这个,剩下的代码就很好理解了,我不说大家都能看懂。

2.10尾插、尾删

尾插和尾删我们都可以采用现代方法来写,也就是吃现成的。

3.0拷贝构造函数

一般的拷贝构造函数我们可以这么去写,这种思路很巧妙代码也很容易看懂。重点是我们下面几种的拷贝构造函数。

这种写法可以支持我们的list像数组一样赋值,因为单参数传参会有隐式类型转换,我们括号里的内容会被转换成initializer_list<T>类型,然后就可以像上一步部一样操作了。注意这里是用auto&,这是为了避免像string这种类型出差错而采用的别名。

上面这种是因为STL标准库中vector也有这样一中重载写法,它是采用迭代器来进行传值,first和last都是我们的迭代器类型。写成模板是因为迭代器还有一种const属性的。

这是重载的另一种版本,开n个空间的大小,用第二个参数自动填充,为什么要写两个呢,第一个n的类型是size_t,第二个n的类型是int,这是因为倘若我们传两个int类型的,如果没有下面这种它就要进行类型转换,但是我们上面还有一种函数模板,所以我们的编译器此时就会去使用那个函数模板,但是那个我们是针对迭代器类型的,所以结果会发生什么大家应该都猜到了吧,所以为了规避那种情况我们就重载了两个方式。

3.1赋值运算符重载

赋值运算符重载我们借用了拷贝构造函数,因为我们的参数是形参且没有使用引用,所以会自动调用拷贝构造函数,然后我们直接交换数据就可以了。由于v是拷贝构造出来的,数以改变v不会对原对象有任何影响,且其生命周期只在这个函数内,出了这个函数就自动调用析构函数销毁了。

  • 34
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
引用和提供了关于实现vector的两种方法。其中,引用展示了一个使用reserve和push_back方法的示例,而引用展示了一个使用new和memcpy函数的示例。这两种方法都是常见的实现vector的方式。 在第一种方法中,通过reserve函数可以预留足够的内存空间,然后使用push_back函数逐个将元素添加到vector中。这种方法的好处是可以避免不必要的内存重分配,提高了效率。 而第二种方法使用new操作符在堆上分配内存空间,并使用memcpy函数将已有的vector对象的数据复制到新的内存空间中。通过这种方式,可以实现深拷贝,即两个vector对象拥有独立的内存空间。这种方法的好处是可以在不修改原始vector对象的情况下创建一个新的vector对象。 除了以上两种方法,还可以使用其他方式实现vector类。例如,可以使用动态数组来实现vector的底层数据结构,然后通过成员函数实现vector的各种操作,如增加、删除、查找等。 总结来说,c语言模拟实现vector的关键是动态内存管理和对元素的增删改查操作。可以使用预留空间和逐个添加元素的方式,也可以使用动态数组和复制数据的方式来实现vector类。具体的实现方式可以根据需求和实际情况选择。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++——vector模拟实现](https://blog.csdn.net/weixin_49449676/article/details/126813526)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值