代码仓库:yanglianoo/My_STL at timer (github.com)
1.Vector 概述
在C++ STL(标准模板库)中,vector
是一个动态数组容器,它是一个模板类具有以下特性:
- 动态大小:
vector
的大小可以根据需要动态增长或缩小。它可以自动调整内部存储空间,以适应容器中元素的数量。
- 连续存储:
vector
中的元素在内存中是连续存储的,这使得对元素的随机访问变得高效。
- 快速插入和删除: 在
vector
的末尾插入或删除元素是高效的,时间复杂度为常数。但在中间或开头插入或删除元素的操作可能会导致元素的移动,时间复杂度为线性。
- 随机访问:
vector
支持通过索引进行随机访问。可以使用下标运算符 []
或 at()
函数来访问特定位置的元素。
- 动态调整内存: 当
vector
的大小超过当前分配的内存空间时,它会重新分配更大的内存块,并将现有元素移动到新的内存中。这可以确保容器始终具有足够的内存来存储元素。
- 元素访问: 可以使用迭代器来遍历
vector
中的元素。可以使用 begin()
和 end()
成员函数获取指向容器开头和结尾的迭代器。
- 容器操作:
vector
支持许多常见的容器操作,如排序、查找、插入和删除元素。它还提供了与其他容器兼容的接口,例如迭代器、范围构造函数和算法函数。
STL
库中vector
的定义如下:
template< class T,class Allocator = std::allocator<T>> class vector;
|
参考链接: std::vector - cppreference.com
2.构造Vector
自己手写vector
时,迭代器不是通用的Allocator
类型,需要在vector
内部实现一个自定义的迭代器
vector模板类定义如下,需要维护三个私有的成员变量
template<typename T> class vector { private: int _size; int _capacity; T* _elem; }
|
注意:模板类的实现和声明不能分离编译,因此最好将模板类的声明和实现都放在头文件中
参考链接:(64条消息) C++中模板类的编译过程_c++模板编译_jiazhucai的博客-CSDN博客
2.1构造函数
构造函数定义:
vector(); vector(std::initiallizer_list<T> init) vector(const vector<T>& other); vector(const vector<T>& other,int left,int right); vector(size_t count, T& value);
|
2.1.1 辅助函数
在定义构造函数具体实现时需要定义几个辅助函数:
protected: void expand(); void shrink(); void copyFrom ( T const* A, int left, int right );
|
#define DEFAULT_CAPACITY 3 template <typename T> void vector<T>::expand() {
if(_size <= _capacity) return; if(_capacity < DEFAULT_CAPACITY) _capacity = DEFAULT_CAPACITY; while (_capacity < _size) { _capacity *=2; } T* old_data = _data; _data = new T[_capacity << 1]; for(int i=0;i<_size; i++) { _data[i] = old_data[i]; } delete[] old_data; }
|
template <typename T> void vector<T>::shrink() { if(_capacity < DEFAULT_CAPACITY << 1) return; if(_size << 2 > _capacity) return;
T* old_data = _data; _data = new T[_capacity >> 1]; for(size_t i = 0; i < _size; i++) { _data[i] = old_data[i]; } delete[] old_data; }
|
- 区间复制函数
copyFrom ( T const* A, int left, int right )
template <typename T> void vector<T>::copyFrom ( T const* A, int left, int right ) { if(_data != nullptr) { delete [] _data; _data = nullptr; } _capacity = (right - left) * 2; _size = 0; _data = new T[_capacity];
while (left < right) { _data[_size] = A[left]; _size++; left++; } }
|
2.2.2 构造函数实现
template<typename T> vector<T>::vector():_data(nullptr),_capacity(0),_size(0){}
|
vector(const vector<T>& *other*)
template <typename T> vector<T>::vector(const vector<T>& other) { copyFrom(other._data,0,other._size); }
|
vector(std::initializer_list<T> *init*)
template <typename T> vector<T>::vector(std::initializer_list<T> init) { _size = init.size(); _capacity = _size * 2; int i = 0; _data = new T[_capacity]; for(const auto & elem : init) { _data[i++] = elem; } }
|
vector(int *count*, T& *value*)
template <typename T> vector<T>::vector(size_t count, T& value) { _size = count; _capacity = 2 * _size; _data = new T[_capacity]; for(size_t i =0; i<count;i++) { _data[i] = value; } }
|
2.2 析构函数
template<typename T> vector<T>::~vector() { if(_data != nullptr) { delete [] _data; _data = nullptr; } _size = 0; _capacity = 0; }
|
3.赋值
实现的成员函数如下:
public: vector& operator=(const vector& other); vector& operator=( std::initializer_list<T> ilist );
void assign(size_t count,const T& value); void assign(std::initializer_list<T> ilist );
|
vector& operator=(const vector& other)
template <typename T> vector<T>& vector<T>::operator=(const vector& other) { copyFrom(other._data,0,other._size); return *this; }
|
vector<T>::operator=( std::initializer_list<T> *ilist* )
template <typename T> vector<T>& vector<T>::operator=( std::initializer_list<T> ilist ) { if(_data != nullptr) { delete [] _data; _data = nullptr; } _size = ilist.size(); _capacity = _size * 2; int i = 0; _data = new T[_capacity]; for(const auto & elem : ilist) { _data[i++] = elem; } return *this; }
|
4.元素访问
元素访问的接口有如下这些:
public: T& at(size_t index); T& operator[](size_t index); T& front(); T& back(); T* data();
|
具体实现如下:
template <typename T> T& vector<T>::at(size_t index) { if(index <0 || index >= _size) { throw std::logic_error("out of range"); } return _data[index]; }
template <typename T> T& vector<T>::operator[](size_t index) { return this->at(index); }
template <typename T> T& vector<T>::front() { return _data[0]; }
template <typename T> T& vector<T>::back() { if (_size <= 0) { throw std::logic_error("vector is empty"); } return _data[_size-1]; }
template <typename T> T* vector<T>::data() { return _data; }
|
5.迭代器
5.1 迭代器使用实例
在构建迭代器之前,先看看迭代器的用法,一般用于遍历容器中的各个元素
#include <iostream> #include <vector>
int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; std::cout << "1. Iterate using iterators: "; for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << "2. Iterate using auto keyword: "; for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << "3. Iterate using range-based loop: "; for (const auto& element : vec) { std::cout << element << " "; } std::cout << "4. Modify elements using iterators: "; for (auto it = vec.begin(); it != vec.end(); ++it) { *it = *it * 2; } for (const auto& element : vec) { std::cout << element << " "; } std::cout << "5. Insert elements using iterators: "; auto insertPos = vec.begin() + 2; vec.insert(insertPos, 10); for (const auto& element : vec) { std::cout << element << " "; } std::cout << "6. Erase elements using iterators: "; auto erasePos = vec.begin() + 1; vec.erase(erasePos); for (const auto& element : vec) { std::cout << element << " "; } return 0; }
|
5.2 迭代器类实现
iterrator
是一个类,在内部维护了一个指针,需要对其进行各种操作符重载,iterrator
的具体实现如下:
public: class Iterrator { private: T * m_pointer; public: Iterrator():m_pointer(nullptr) {} Iterrator(T * pointer) : m_pointer(pointer) {} ~Iterrator() {} bool operator == (const Iterrator & other) { return m_pointer == other.m_pointer; } Iterrator operator = (const Iterrator& other) { m_pointer = other.m_pointer; }
Iterrator & operator ++ () { m_pointer +=1; return *this; }
Iterrator operator ++ (int) { Iterrator it = *this; ++(*this); return it; }
Iterrator operator + (int i) { Iterrator it = *this; it.m_pointer += i; return it; } Iterrator operator += (int i) { m_pointer += i; return *this; }
Iterrator operator -= (int i) { m_pointer -= i; return *this; }
Iterrator operator - (int i) { Iterrator it = *this; it.m_pointer -= i; return it; }
int operator - (const Iterrator& other) const { return m_pointer - other.m_pointer; }
T & operator * () { return *m_pointer; }
T * operator -> () { return m_pointer; } };
|
记录:在对Iterrator
前++和后++重载时,如下:
Iterrator & operator ++ () { m_pointer +=1; return *this; } Iterrator operator ++ (int) { Iterrator it = *this; ++(*this); return it; }
|
在C++中,后缀递增操作符(it++)可以通过接受一个额外的int参数进行区分,这是由C++语言规范所定义的。根据规范,后缀递增操作符的函数参数列表中必须有一个int类型的参数,尽管在函数体内并没有使用该参数。
这种设计是为了在语法上能够区分前缀递增和后缀递增操作。当编译器遇到it++
表达式时,它会根据后缀递增操作符的函数参数列表中是否存在一个额外的int参数来决定使用后缀递增操作符的重载函数。
编译器会将后缀递增操作符的调用转换为对重载的后缀递增操作符函数的调用,并传递一个编译器生成的临时整数参数(通常是0)。
请注意,这个整数参数的名称在函数体内并没有使用,因为它的存在只是为了与前缀递增操作符进行区分,而不是为了实际使用。
5.3 迭代器操作函数实现
begin
用于获取头指针,end
用于获取尾指针
public: Iterator begin(); Iterator end();
|
具体实现如下:
template <typename T> typename vector<T>::Iterator vector<T>::begin() { vector<T>::Iterator it(_data); return it; }
template <typename T> typename vector<T>::Iterator vector<T>::end() { vector<T>::Iterator it(_data + _size); return it; }
|
这里需要使用typename
显示的告诉编译器vector<T>::Iterator
是一个类型
6.容量
和容量相关的接口函数比较简单,实现的接口如下:
public: bool empty() const; size_t size() const; size_t max_size() const; void reserve(size_t new_cap); size_t capacity() const; void shrink_to_fit();
|
template <typename T> bool vector<T>::empty() const { return _size==0; }
template <typename T> size_t vector<T>::size() const { return _size; }
template <typename T> size_t vector<T>::max_size() const { return _capacity; }
template <typename T> size_t vector<T>::capacity() const { return _capacity; }
template <typename T> void vector<T>::reserve(size_t new_cap) { if(_capacity >= new_cap) { return; } else { _size += new_cap; expand(); } }
template <typename T> void vector<T>::shrink_to_fit() { shrink(); }
|
7.修改器
和修改容器有关的接口函数如下:
public: void clear(); Iterator insert(const Iterator it ,const T & value); Iterator insert(const Iterator it ,int n,const T & value); Iterator erase(const Iterator it); Iterator erase(const Iterator first,const Iterator last); void push_back(const T & value); void pop_back(); void resize(size_t size); void swap(vector & other);
|
template <typename T> void vector<T>::clear() { if (_size <= 0) { throw std::logic_error("vector is empty"); } _size = 0; }
|
Iterator insert(const Iterator it ,int n,const T & value)
template <typename T> typename vector<T>::Iterator vector<T>::insert(const Iterator it ,int n,const T & value) { int size = it - begin(); _size += n; expand(); for(size_t i=_size; i>size;i--) { _data[i+n-1] = _data[i-1]; } for(size_t i=0; i<n;i++) { _data[size+i] = value; } return vector<T>::Iterator(_data + size); }
|
Iterator insert(const Iterator it ,const T & value)
template <typename T> typename vector<T>::Iterator vector<T>::insert(const Iterator it ,const T & value) { _size+=1; expand(); insert(it,1,value); }
|
Iterator erase(const Iterator it)
template <typename T> typename vector<T>::Iterator vector<T>::erase(const Iterator it) { if(end() - it == 1) { _size -= 1; return end(); } int count = it - begin(); for(size_t i = count; i < _size -1 ; i++) { _data[i] = _data[i+1]; } _size -= 1; return it; }
|
Iterator erase(const Iterator first,const Iterator last)
template <typename T> typename vector<T>::Iterator vector<T>::erase(const Iterator first,const Iterator last) { if( first == last) { return first; } else { int f = first - begin(); int l = last - begin(); while ( l < _size) { _data[f++] = _data[l++]; } _size = f; shrink(); return first; } }
|
void push_back(const T & value)
template <typename T> void vector<T>::push_back(const T& value) { if(_size < _capacity) { _data[_size] = value; _size++; return; } else { _size++; expand(); int index = _size - 1; _data[index] = value; } }
|
template <typename T> void vector<T>::pop_back() { if(_size != 0) { _size--; } }
|
template <typename T> void vector<T>::resize(size_t size) { if(_size > size) { _size = size; return; }
if(size <= _capacity) { for(size_t i= _size; i < size; i++) { _data[i] = T(); } _size = size; return; } _size = size; expand(); }
|
void swap(vector & other)
template <typename T> void vector<T>::swap(vector & other) { T * data = other._data; int size = other._size; int capacity = other._capacity;
other._data = _data; other._size = _size; other._capacity = _capacity;
_data = data; _size = size; _capacity = capacity; }
|
8.结束语
至此,vector
构造完毕,未进行测试,不知道是否有bug