首先,关于allocator戳旁边→维基百科-分配器(C++)
这次我只用了其中的一部分API,来实现一个简易的vector容器,这个简易版vector实现了插入、删除、查找等简易功能,由于对右值的理解不足,所以这次并未实现关于右值的API。
【MSDN-class allocator_base API】
此次用到的有:
- allocate - 用于分配、再分配空间
- construct - 用于构造对象
- destroy - 用于销毁对象(调用其构造函数)
接下来开始,用例子一点点的说明如何使用allocator来编写一个vector类。
完整的源码在最下面可以下载。
首先,先给出一些typedef
typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef ptrdiff_t different_type;
其中T为typename,此处还用了指向T的指针来实现迭代器的用途。在使用typedef后,可更方便的理解代码,增强可读性。
关于这个Vector类中的allocator,我选择了包含而非私有继承的方式,个人感觉这样的代码可读性更高,更易于修改维护。
类的私有部分,有如下四个成员:
//存储区 std::allocator<value_type> _alloc_vec; //指向首位的指针 pointer _first; //指向末位的指针 pointer _last; //记录当前容量 size_type _capacity;
allocator用来分配内存,存储元素;两个T*类型的指针分别指向Vector的开始以及结尾;size_type类型的_capacity则用来记录Vector的当前容量,在容量不足时就扩充。
然后是成员函数,成员函数我是根据MSDN上提供的来编写的,所以全是公有成员函数,但是也足够完成这个简易的类了。
首先,构造函数、复制构造函数、析构函数以及重载的‘=‘符号
//默认构造函数 Vector(size_type _size = 256) : _first(_alloc_vec.allocate(_size)), _last(_first), _capacity(_size) { } //复制构造函数 Vector(const Vector& Right) : _first(_alloc_vec.allocate(Right._capacity)), _last(_first), _capacity(Right._capacity) { for (auto p : Right) _alloc_vec.construct(_last++, p); } //默认析构函数 ~Vector() = default; //重载‘=‘ Vector& operator=(const Vector<T>& Right) { return Vector(Right); }
默认构造函数用了一个默认大小为256的_size参数来初始化对象,预分配一个不算太小的内存空间,也方便将来扩充。
_first(_alloc_vec.allocate(_size))
这一句的作用,等同于
_first = _alloc_vec.allocate(_size);
即给_alloc_vec分配一个大小为_size的空间,并且将_first指向其首位。具体函数声明请戳MSDN。
之后,由于没有给对象中添加元素,所以_last与_first指向相同的地址,即_alloc_vec的首位,然后将_size的值存入_capacity。
关于拷贝构造函数,先是用capacity()函数来获取Right的容量,然后让调用对象分配一个相同大小的空间,并且将两个指针都指向其首位,然后记录容器大小,接着进入函数体,用for循环将Right中的元素都拷贝至调用对象中,并且修改_last指向的位置。
注意,无论是何种构造函数,_last指向的位置都是最后一个元素的下一位。
至于析构函数则直接使用默认析构函数,而等号就直接调用复制构造函数。(才不是因为偷懒
然后是pop_back()以及push_back()这两个较容易实现的成员函数。
//删除末尾元素 void pop_back() { _alloc_vec.destroy(--_last); } //将元素插入末位 void push_back(reference val) { if (size() >= _capacity) { _alloc_vec.allocate(_capacity); _capacity *= 2; } _alloc_vec.construct(_last++, val); }
pop_back()中调用了destroy函数,这个函数将会调用自减1之后的_last指针所指向的对象的析构函数,销毁该对象,而这一动作完成后,_last仍旧指向最后一位元素的下一位。
push_back()在将元素加入Vector之前,会检查容量是否足够分配空间,若是不够,则调用allocate来分配更多的空间;将元素加入,调用了construct,这个函数将调用类型为T的构造函数,并且在将其加入之后,将_last后移一位。
然后好像那三个函数就介绍完了……剩下的Vector中的insert和erase函数也就是运用了与push_back以及pop_back类似的方法……所以就不写了。(嗬嗬嗬
至于其他的都是一些对指针的操作……嗯就这样吧……(逃
【完整源码下载】