阅读《STL源码剖析》有感,根据vector特性,基于数组,手动模拟一个vector。首先定义几个typedef,方便指针的定义。
templateclass Vector { public: typedef T value_type; typedef value_type* pointer; typedef value_type* iterator; typedef value_type& reference; public: typedef T value_type; typedef value_type* pointer; typedef value_type* iterator; typedef value_type& reference; protected: iterator start; //表示目前使用空间的头 iterator finish; //目前使用空间的尾 iterator end_of_storage; //目前可用空间的尾 };
定义一个迭代器类型iterator(指针),之后定义三个迭代器,start(表示目前使用空间的头)、finish(目前使用空间的尾)、end_of_storage(目前可用空间的尾)。之后通过对指针的操作,以及数组的扩容模拟vector。全部源码如下:
//Vector.h #pragma once #includetemplate class Vector { public: typedef T value_type; typedef value_type* pointer; typedef value_type* iterator; typedef value_type& reference; public: Vector(int lenght = 0) :start(nullptr), finish(nullptr), end_of_storage(nullptr) { start = new value_type[lenght]; finish = start; end_of_storage = &start[lenght]; } ~Vector() { delete[]start; start = nullptr; } public: iterator begin() { return start; } iterator end() { return finish; } int size() { return static_cast (end() - begin()); } void push_back(const T & x) { if (finish != end_of_storage) { *finish = x; finish++; } else { int num = size(); if (num <1) { iterator newstart = new value_type[2]; delete []start; start = nullptr; start = newstart; finish = start; end_of_storage = &start[2]; *finish = x; finish++; } else { iterator newstart = new value_type[num * 2]; memcpy(newstart,start, sizeof(value_type) * num); delete[]start; start = nullptr; start = newstart; finish = start+num; *finish = x; end_of_storage = &start[num * 2]; finish++; } } } void pop_back() { if (finish != start) { finish--; } } reference operator[](int n) { return *(begin() + n); } iterator erase( const iterator position) { if (position + 1 != end()) { int num = static_cast (finish - (position+1)); memmove(position, position+1, sizeof(value_type)*(num)); } --finish; return position; } iterator erase(iterator first, iterator last)//[first,last) { if (first + 1 != end()) { int num = static_cast (finish - last); memmove(first, last, sizeof(value_type)*(num)); finish = finish - (last - first); } return first; } void clear() { erase(begin(),end()); } int capacity() { return static_cast (end_of_storage - begin()); } protected: iterator start; //表示目前使用空间的头 iterator finish; //目前使用空间的尾 iterator end_of_storage; //目前可用空间的尾 private: };
在vector的构造函数中,通过传入的参数,开辟空间大小。默认参数为零。在构造函数中,start和finish指针,指向开辟空间的首地址,end_of_storage指向最后的地址。begin()和end() ,分贝返回start指针和finish指针。push_back()函数,在传入值时,所占空间已满,开辟之前二倍的空间,并将之前的值拷贝到刚开辟的空间中,同时,释放原来的空间,finish指针向后移动。pop_back()函数实现较为简单,将finish指针向前移动。其他的各个操作,都是对指针操作得到结果。测试代码:
#include#include "Vector.h" int main() { Vector vector; vector.push_back(1); vector.push_back(2); vector.push_back(3); vector.push_back(4); vector.push_back(5); int temp = vector.size(); int temp1 = vector.capacity(); printf("输入的元素:n"); for (Vector ::iterator item = vector.begin();item !=vector.end();item++) { printf("%dn",*item); } printf("所存数据 = %d,空间所占大小 = %dn", temp, temp1); vector.pop_back(); vector.pop_back(); vector.pop_back(); vector.pop_back(); int temp3 = vector.size(); int temp4 = vector.capacity(); printf("出栈后剩余的元素:n"); for (Vector ::iterator item = vector.begin(); item != vector.end(); item++) { printf("%dn", *item); } printf("所存数据 = %d,空间所占大小 = %dn", temp3, temp4); return 0; }
输出结果:
最后聊聊erase() 成员函数,此函数,在STL vector中,通过vs2015测试时,通过迭代器删除一个元素时,不管它 “ * ”取值,还是++操作,都会崩溃。
for (std::vector::iterator item =hvector.begin();item!=hvector.end();item++) { printf("%dn", *item); if (*item == 3) { hvector.erase(item); int i = *item;//崩溃 } //item++时崩溃 }
网上更多的说法,item被删除掉,成了野指针。但是当我看见《STL源码剖析》时,erase()的实现如下:
在这里只是进行了位置的偏移,同时释放掉最后一个元素。(至此,我在模拟时,也进行了位置的偏移), 从这里可以看到,并不是因为野指针的缘故。
参看这篇博客C++ vector容器erase操作后iterate失效真相 ,这里作者提到vs中erase()参数是const_iterator,所以++时会报错。我没理解到作者的观点。各位读者知道后,请互相交流学习一下,十分感激。网上众说纷纭,自己也没找到很有说服力的答案。至此,技术有限,这里留下一个疑点。我怀疑可能是,内存发生了改动,导致迭代器失效报错。
如果读者不想复制粘贴,可下载:
源码:模拟vector的简易实现-C++文档类资源-CSDN下载



