C++手动实现vector及代码细节详解
使用c++实现vector容器,并对部分细节做了解释
文章目录
vector中的成员函数总结
函数名 | 功能 |
---|---|
vector() | 构造函数 |
~vector() | 析构函数 |
vector(const vector& vec) | 拷贝构造函数 |
vector& operator=(const vector& vec) | 赋值运算符重载函数 |
value_type& operator[](size_t index) | []运算符重载函数(用于取出vector实例化对象的第index个元素) |
bool operator==(const vector& vec)const | ==运算符重载函数(用于判断两个vector对象是否相等) |
void push_back(value_type val) | 向vector示例化对象增添元素 |
void pop_back() | 删除vector实例化对象最后一个元素 |
void insert(iterator it,value_type val) | 向vector实例化对象的it位置插入一个元素 |
void erase(iterator it) | 删除vector实例化对象it位置的元素 |
value_type front()const | 取出vector对象中的第一个元素 |
value_type back()const | 取出vector对象中的最后一个元素 |
iterator begin() | 获取vector实例化对象的元素首地址 |
iterator end() | 获取vector实例化对象的最后一个元素的下一个地址 |
size_t size()const | 获取vector实例化对象的元素个数 |
size_t capacity()const | 获取vector实例化对象所占空间大小 |
bool empty() | 判断vector实例化对象是否为空 |
vector中的成员变量
首先为了实现vector可以实例化任意数据类型的对象,我们需要对它进行模板化,在类的定义之前增加如下语句:
template<typename T>
如我们想要实例化一个int
型vector的时候,使用vector<int> vec
,此时模板中的T
就是指int
型数据类型,那么T*
就是指int*
数据类型。
以下就是我们实现vector所用到的成员变量:
- _data : 用于申请一段连续空间的指针
- _size : 用于存放该vector对象中存放元素的个数
- _capacity : 用于存放vector对象所申请的空间大小
该部分相关代码如下:
public:
typedef T value_type; // 这个并不是成员变量,主要时为了增强可读性
typedef T* iterator; // 其时就是重新起别名
private:
value_type* _data;
size_t _size;
size_t _capacity;
我们来解释一下_capacity
参数。若没有该参数,每增添一个新的元素,就需要重新申请空间存放新的元素,这会消耗较多时间,效率不高。故而在实现的时候我们采用倍增的方式提前申请较大空间,倍增的意思就是当元素个数大于空间大小时,申请的空间将会是原空间的二倍,元素个数和所申请的空间的大小对比如下:
元素个数 空间大小
1 1
2 2
3 4
4 4
5 8
使用这种方式申请空间,当元素个数越来越多,所需申请的次数相对之前的申请方式会越来越小。
构造函数
构造函数主要用创建对象时对成员变量进行初始化
在该部分的实现涉及了初始化列表的相关知识。具体格式为在构造函数名后面使用:变量名(初始化值), ...
,需要特别注意的是,初始化列表的初始化顺序并不是由构造函数后的变量顺序决定的,而是由类中成员变量的定义顺序决定的。
vector():_data(NULL),_size(0),_capacity(0){}
析构函数
析构函数主要用于释放为实例化对象所分配的空间,当某个对象离开自己的作用域时就会自动调用析构函数,释放空间。
这里涉及一个一个知识点为,如何使用delete
释放数组所占空间,必须使用delete [] 数组名
来释放数组空间,单独delete 数组名
只会释放数组中的第一个元素的空间。
相关代码如下:
~vector(){
delete [] _data;
_data = NULL;
_size = 0;
_capacity = 0;
}
拷贝构造函数
拷贝构造函数主要功能为:用于实现
vector<int> vec1 = vec2
该代码功能,即实例化一个对象的时,使用另外一个对象的成员变量初始化该对象。
相关代码如下:
vector(const vector& vec){
_size = vec._size;
_capacity = vec._capacity;
_data = new value_type[_capacity];
for(int i=0;i<_size;++i){
_data[i] = vec._data[i];
}
}
如果要细究,这里其实涉及引用,const等相关知识。如果对此有疑惑,建议可以查阅相关资料。
运算符重载函数
该部分重载的运算符有:
=
,[]
,==
。运算符重载函数的函数名格式为返回值 operator运算符(传入的参数)
。
我们以==
运算符重载为例子,该运算符功能为判断两个对象是否相等,所以返回值为bool
型,传入参数为进行比较的另外一个对象,故而函数名为bool operator==(const vector& vec)const
。其中的const
指的是所传入的参数是不可修改的。
赋值运算符重载函数
赋值运算符重载函数时将传入参数的所有信息拷贝一份。
针对vector而言,赋值运算符重载函数具体实现的是vec1 = ve2;
,按函数调用来理解就是vec1.operator=(vec2)
。
具体代码如下:
vector& operator=(const vector& vec){
if(this == &vec) return *this;
value_type* temp = new value_type[vec._capacity];
for(int i=0;i<vec._size;++i){
temp[i] = vec._data[i];
}
delete [] _data;
_data = temp;
_size = vec._size;
_capacity = vec._capacity;
return *this;
}
[]运算符重载函数
针对vector而言,[]
运算符重载函数具体实现的是vec[0];
,按函数调用来理解就是vec.operator[](0)
。
具体代码如下:
value_type& operator[](size_t index){
return _data[index];
}
==运算符重载函数
针对vector而言,[]
运算符重载函数具体实现的是vec1 == vec2;
,该判断成立成返回true,不成立返回false。按函数调用来理解就是vec1.operator==(vec2)
。
具体代码如下:
bool operator==(const vector& vec)const{
if(_size!=vec._size) return false;
for(int i=0; i<_size; ++i){
if(_data[i]!=vec._data[i])
return false;
}
return true;
}
增添元素
该部分分为两种。一种是默认位置增添,也就是在_data的末尾增添元素,对应实现的函数名为push_back
;另一种是指定位置增添,也就是说在_data的it位置插入一个元素对应实现的函数名为insert
。
这两个函数的总体思路都是向一个连续空间中增添元素,我们需要将插入的位置至最后一个元素统一向后移动一个位置,从而空出一个位置用于存放新元素。在此我们也会实现倍增的方式申请空间,即_capacity *=2;
,这里需要特别处理的是当原本的vec是空的时候,我们无法使用该代码来统一处理。具体如下:
push_back
相关代码如下:
void push_back(value_type val){
if(0==_capacity) {
_capacity = 1;
_data = new value_type[1];
} else if(_size+1 > _capacity){
_capacity *=2;
value_type* temp = new value_type[_capacity];
for(int i=0; i<_size; ++i){
temp[i] = _data[i];
}
delete [] _data;
_data = temp;
}
_data[_size] = val;
++_size;
}
insert
相关代码如下:
void insert(iterator it, value_type val){
int index=it-_data;
if(0==_capacity){
_capacity = 1;
_data = new value_type[1];
_data[0] = val;
}else if(_size+1 > _capacity){
_capacity *= 2;
value_type* temp = new value_type[_capacity];
for(int i=0; i<index; ++i){
temp[i] = _data[i];
}
temp[index] = val;
for(int i=index; i<_size; i++){
temp[i+1] = _data[i];
}
delete [] _data;
_data = temp;
}else{
for(int i=_size-1; i>=index; --i){
_data[i+1] = _data[i];
}
_data[index] = val;
}
++_size;
}
删除元素
删除元素分为两种方式。一种为删除末尾元素,所实现的函数名为pop_back
,另一种是指定位置删除元素,所实现的函数名为erase
。
pop_back
void pop_back(){
--_size;
}
earse
void erase(iterator it){
size_t index=it-_data;
for(int i=index; i<_size-1; ++i){
_data[i] = _data[i+1];
}
--_size;
}
其他函数
其他函数功能非常简单,就不多加解释了
value_type front()const
返回vector中的第一个元素
value_type front()const{
return _data[0];
}
value_type back()const
返回vector中的最后一个元素
value_type back()const{
return _data[_size-1];
}
iterator begin()
返回vector中的第一个元素的地址
iterator begin(){ return _data;}
iterator end()
返回vector中的最后一个元素的地址
iterator end(){ return _data+_size;}
size_t size()const
返回vector中的元素个数
size_t size()const{
return _size;
}
size_t capacity()const
返回vector中的所申请空间大小
size_t capacity()const{
return _capacity;
}
bool empty()
判断vector是否为空
bool empty(){
return _size == 0;
}
代码总结
#include <iostream>
#include <algorithm>
#include <numeric>
using namespace std;
namespace miniSTL{
template<typename T>
class vector{
public:
typedef T value_type;
typedef T* iterator;
private:
value_type* _data;
size_t _size;
size_t _capacity;
public:
vector():_data(NULL),_size(0),_capacity(0){}
~vector(){
delete [] _data;
_data = NULL;
_size = 0;
_capacity = 0;
}
vector(const vector& vec){
_size = vec._size;
_capacity = vec._capacity;
_data = new value_type[_capacity];
for(int i=0;i<_size;++i){
_data[i] = vec._data[i];
}
}
vector& operator=(const vector& vec){
if(this == &vec) return *this;
value_type* temp = new value_type[vec._capacity];
for(int i=0;i<vec._size;++i){
temp[i] = vec._data[i];
}
delete [] _data;
_data = temp;
_size = vec._size;
_capacity = vec._capacity;
return *this;
}
void push_back(value_type val){
if(0 == _capacity){
_capacity = 1;
_data = new value_type[1];
}else if(_size+1 > _capacity){
_capacity *= 2;
value_type* temp = new value_type[_capacity];
for(int i=0;i<_size;++i){
temp[i] = _data[i];
}
delete [] _data;
_data = temp;
}
_data[_size] = val;
++_size;
}
void pop_back(){ --_size;}
size_t size()const{ return _size;}
size_t capacity()const { return _capacity;}
bool empty(){ return _size == 0;}
value_type& operator[](size_t index){
return _data[index];
}
bool operator==(const vector& vec)const{
if(_size != vec._size) return false;
for(int i=0;i<_size;++i){
if(_data[i] != vec._data[i]) return false;
}
return true;
}
value_type front()const{ return _data[0];}
value_type back() const{ return _data[_size-1];}
void insert(iterator it,value_type val){
int index = it - _data;
if(0 == _capacity){
_capacity = 1;
_data = new value_type[1];
_data[0] = val;
}else if(_size+1 > _capacity){
_capacity *= 2;
value_type* temp = new value_type[_capacity];
for(int i=0;i<index;++i){
temp[i] = _data[i];
}
temp[index] = val;
for(int i=index;i<_size;++i){
temp[i+1] = _data[i];
}
delete [] _data;
_data = temp;
} else {
for(int i=_size-1;i>=index;--i){
_data[i+1] = _data[i];
}
_data[index] = val;
}
++_size;
}
void erase(iterator it){
size_t index = it - _data;
for(int i=index;i<_size-1;++i){
_data[i] = _data[i+1];
}
--_size;
}
iterator begin(){ return _data; }
iterator end(){ return _data + _size; }
};
}
using namespace miniSTL;
int main(){
vector<string> vecs;
string s;
while(cin >> s){
vecs.push_back(s);
}
for(auto n:vecs){
cout << n <<" ";
}
cout <<endl;
}
更多推荐
所有评论(0)