vector模拟实现

一、整体逻辑

1、构造、析构  push_back()  reserve() size()  capacity()  []

2、使用3个指针的好处 insert erase(0位置时不会死循环,地址一定不为0)  迭代器表示范围

扩容时,指针位置会变,pos变为野指针(函数内外都失效,外部因为传值),导致迭代器实现

注意:inserat以后就不要使用这个pos迭代器了,但是可以通过接收返回值更新pos

3、resize  n个值构造  迭代器区间构造   拷贝构造   赋值重载

二、构造/析构/尾插

1、简单的构造

vector模拟实现_第1张图片

 vector模拟实现_第2张图片

直接将vector的3个指针成员置空即可。

可以使用C++11中的缺省值,在初始化列表时就会自动完成。

2、析构 

vector模拟实现_第3张图片

 delete[]对于_start指向的一段数据,分别调用析构函数完成清理,最后回收空间。

3、reserve/[]/size/capacity

vector模拟实现_第4张图片

 vector模拟实现_第5张图片

 1、_start非空时才挪动数据,这里挪动数据不能简单的使用memcpy拷贝内存。

如果是自定义类型,一个指针指向开辟的堆空间,memcpy会导致指针的浅拷贝,即指针指向同一块空间,进而导致多次析构报错。

应该采用循环赋值的方法,每次都调用vector中类型T的赋值运算符重载函数(对象数组中的每个对象分别调用),在重载函数中会完成深拷贝。

vector模拟实现_第6张图片 2、最好提前保存一下sz,即元素个数。因为扩容后_start和_finish  _end_of_storage就没有关系了,若此时再调用size()得到个数是不准确的。

三、insert/erase

1、insert

vector模拟实现_第7张图片

 利用迭代器pos指定要插入的位置,此时如果要扩容,就会导致迭代器失效(函数内部失效)

即pos还在原来_start那一段空间的某个位置,扩容后,_start重新指向一块空间,再在pos位置插入就是错误的。

可以先用gap保存一下pos的相对位置,如果扩容,就更新一下pos

最后返回pos即更新后的位置

2、erase

vector模拟实现_第8张图片

返回pos,即删除那个元素的下一个位置的元素。 

总结:对于vector,使用erase和insert迭代器对象后,迭代器就会失效,不能再访问,访问的结果是未定义的。但是可以在insert和erase后接收返回值来更新迭代器(外部)。

四、resize/区间/拷贝/=

1、resize

vector模拟实现_第9张图片

插入n个val,可以使用不用传参默认构造的T()匿名对象作为缺省值。

C++中,将内置类型升级,即int  double等,也可以生成T()的匿名对象。

n<=size()时,直接调整_finish的位置即可,不用抹除数据。

n>size()时,先reserve(n),reserve内会判断n是否大于capacity(),如果需要,就进行扩容。

然后进行循环赋值插入,或复用尾插。

vector模拟实现_第10张图片 

也可以完成n个val的初始化,复用resize即可。

2、迭代器区间构造

vector模拟实现_第11张图片

定义一个新的模板参数InputIterator,first和last表示要插入的迭代器区间,可以是别的类型的迭代器,因此重新定义为InputIterator。

3、拷贝构造

vector模拟实现_第12张图片

循环赋值或复用尾插 

4、=重载

vector模拟实现_第13张图片

 使用现代写法,先让调用拷贝构造得到形参v,然后交换。

目录

一、整体逻辑

二、构造/析构/尾插

1、简单的构造

2、析构 

3、reserve/[]/size/capacity

三、insert/erase

1、insert

2、erase

四、resize/区间/拷贝/=

1、resize

2、迭代器区间构造

3、拷贝构造

4、=重载


 

你可能感兴趣的:(算法,数据结构)