一 vector的大致框架
1.1 框架
vector的成员变量不再是我们熟悉的size,capacity,而是变成了功能一致的三个指针:_start,_finish,_endofstorage,三个指针的作用如下:
同时,因为其本身指针的特性,其迭代器也是返回其内部的指针就可以了,因此我们可以直接定义迭代器。
大致框架如下:
namespace My
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start;iterator _finish;iterator _endofstorage;};
}
1.2 默认构造函数
实际上,我们可以在底层初始化给三个指针都赋值为nullptr,这样默认构造就可以什么都不敢,并且在初始化时就全都赋值为nullptr,可以使代码更加简练。
代码如下:
//构造函数vector() {}
private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;
1.3 析构函数
delete掉空间,将三个指针再次赋值为nullptr即可。
//析构 ~vector() {delete[] _start; //注意一定要加[],因为有可能存的值是一个数组_start = _finish = _endofstorage = nullptr;}
二 vector的容量操作
2.1 size函数
一般的容器,我们都有size和capacity两个函数 来获取其容器大小,在vector中我们也有这两个函数,这里我们通过 指针-指针的差值来 计算其实际值。
代码如下:
size_t size() const {return _finish - _start;}
2.2 capacity函数
代码如下:
size_t capacity() const {return _endofstorage - _start;
}size_t capacity() const {return _endofstorage - _start;
}
2.3 reserve函数
在库中,reserve 修改容量时,size 是不会发生变化的(因为有效元素个数不变),若空间容量扩大则 capacity 会相应的进行扩大,若空间容量缩小时 capacity 是不会发生变化的。
reserve的思想就是把原来的空间舍弃掉,重新开一段大空间。
代码如下:
//扩容void reserve( size_t n) {if (n > capacity()) {//开始扩容T* tmp = new T[n];size_t sz = size();//提前算出size(),用来把原值赋值给新空间if (_start) {for (size_t i = 0; i < sz; i++) {tmp[i] = _start[i];}delete[] _start;//避免内存泄漏}//指针指向新空间_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}
2.4 resize函数
resize 修改有效元素个数时,size 会进行相应的扩大或缩小变化,capacity 不一定会变化(有效元素增多时,若容量足够则capacity不变,否则会扩容;有效元素减少时,capacity 不变)
resize的两个操作如下:
- 1.如果n小于当前的size,则数据个数缩小到n
- 2.如果n大于于当前的size,则说明空间不够需要增容,并且将size扩大到n
注意,这里val得用T的默认构造。
代码示例:
//resizevoid resize(size_t n, const T& val = T()) {if (n <= size()) {_finish = _start + n;}else {reserve(n);while (_finish < _start + n) {*_finish = val;++_finish;}}}
三迭代器
vector的迭代器就是原生指针,因此直接返回指针即可:
typedef T* iterator;
typedef const T* const_iterator;iterator begin() {return _start;
}iterator end() {return _finish;
}const_iterator begin() const {return _start;
}const_iterator end() const {return _finish;
}
四 元素修改函数
4.1 insert函数
在指定pos位置进行插入元素
但是这里却有一个很坑的点,那就是不小心写出来的代码就会引起迭代器失效的问题。
因为插入后,我们可能会发生扩容,pos指针会失效,这里我们先记录一下pos位置和起始位置的差值,扩容后让pos指针指向新空间。
void insert(iterator pos, const T& val) {assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage) {size_t len = pos - _start; reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *end;--end;}*pos = val;++_finish;}
但要注意,这样的话,外部的pos指针怎么办呢?
这里是值传递,形参的改变是不会改变实参的,所以说外面的pos依旧没有实现更新操作,依旧会失效。
正确写法是通过返回值去解决问题的,返回的是迭代器,即新插入元素的位置。
正确代码为:
iterator insert(iterator pos, const T& val) {assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage) {size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}
4.2 erase()
这里主要的就是从后往前删除的,这点需要大家注意一下。
同时,erase也会发生迭代器失效问题,因此要返回值避免迭代器失效。
代码如下:
iterator erase(iterator pos) {assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it < _finish) {*(it - 1) = *it;++it;}--_finish;return pos;}
4.3 push_back()
插入尾部元素,直接复用insert.
void push_back(const T& val) {insert(end(), val);
}
4.4 pop_back()
删除尾部元素,直接把_finish--就好。
void pop_back(){assert(_start); //注意判空--_finish;}
五 元素访问
5.1 []的重载
直接放回数组中的数据即可
T& operator[](size_t pos) {assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}
六 其它函数
vector(size_t n, const T& val = T()) {reserve(n);for (size_t i = 0; i < n; i++) {push_back(val);}
}vector(int n, const T& val = T()) {reserve(n);for (int i = 0; i < n; i++) {push_back(val);}
}//区间构造
template <class InputIterator>
vector(InputIterator first, InputIterator last) {while (first != last) {push_back(*first);++first;}
}void swap(vector<T>& v) {std::swap(v._start, _start);std::swap(v._finish, _finish);std::swap(v._endofstorage, _endofstorage);
}//拷贝构造
vector(const vector<T>& v) {reserve(v.capacity());for (auto& x : v) {push_back(x);}
}//移动构造
vector(vector<T>&& v) {swap(v);
}//赋值重载
vector<T>& operator=(const vector<T>& v) {vector<T> tmp(v);swap(tmp);return *this;
}
//移动赋值
vector<T>& operator=(vector<T>&& v) {swap(v);return *this;
}
七 完整代码和测试代码
#pragma once
#include<iostream>
#include<cassert>using namespace std;namespace My {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;iterator begin() {return _start;}iterator end() {return _finish;}const_iterator begin() const {return _start;}const_iterator end() const {return _finish;}//构造函数vector() {}vector(size_t n, const T& val = T()) {reserve(n);for (size_t i = 0; i < n; i++) {push_back(val);}}vector(int n, const T& val = T()) {reserve(n);for (int i = 0; i < n; i++) {push_back(val);}}//区间构造template <class InputIterator>vector(InputIterator first, InputIterator last) {while (first != last) {push_back(*first);++first;}}void swap(vector<T>& v) {std::swap(v._start, _start);std::swap(v._finish, _finish);std::swap(v._endofstorage, _endofstorage);}//拷贝构造vector(const vector<T>& v) {reserve(v.capacity());for (auto& x : v) {push_back(x);}}//移动构造vector(vector<T>&& v) {swap(v);}//赋值重载vector<T>& operator=(const vector<T>& v) {vector<T> tmp(v);swap(tmp);return *this;}//移动赋值vector<T>& operator=(vector<T>&& v) {swap(v);return *this;}//扩容void reserve( size_t n) {if (n > capacity()) {//开始扩容T* tmp = new T[n];size_t sz = size();//提前算出size(),用来把原值赋值给新空间if (_start) {for (size_t i = 0; i < sz; i++) {tmp[i] = _start[i];}delete[] _start;//避免内存泄漏}//指针指向新空间_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}//resizevoid resize(size_t n, const T& val = T()) {if (n <= size()) {_finish = _start + n;}else { reserve(n);while (_finish < _start + n) {*_finish = val;++_finish;}}}iterator insert(iterator pos, const T& val) {assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage) {size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}void push_back(const T& val) {insert(end(), val);}iterator erase(iterator pos) {assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it < _finish) {*(it - 1) = *it;++it;}--_finish;return pos;}void pop_back(){assert(_start); //注意判空--_finish;}T& operator[](size_t pos) {assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}size_t capacity() const {return _endofstorage - _start;}size_t size() const {return _finish - _start;}//析构 ~vector() {delete[] _start; //注意一定要加[]_start = _finish = _endofstorage = nullptr;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};void test_vector1(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();while (it != v.end()){*it *= 10;cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;}void test_vector2(){int i = 0;int j(1);int k = int(2);vector<int*> v1;v1.resize(10);vector<string> v2;//v2.resize(10, string("xxx"));v2.resize(10, "xxx");for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}cout << endl;}void test_vector3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);v.push_back(7);for (auto e : v){cout << e << " ";}cout << endl;vector<int>::iterator it = v.begin() + 2;v.insert(it, 30);for (auto e : v){cout << e << " ";}cout << endl;//v.insert(v.begin(), 30);v.insert(v.begin() + 3, 30);for (auto e : v){cout << e << " ";}cout << endl;}void test_vector4(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);v.push_back(7);for (auto e : v){cout << e << " ";}cout << endl;auto pos = v.begin();v.erase(pos);for (auto e : v){cout << e << " ";}cout << endl;v.erase(v.begin() + 3);for (auto e : v){cout << e << " ";}cout << endl;}//void test_vector5()//{// // 1 2 3 4 5// // 1 2 3 4 5 6// // 2 2 3 4 5// std::vector<int> v;// v.push_back(1);// v.push_back(2);// v.push_back(3);// v.push_back(4);// v.push_back(5);// //v.push_back(6);// for (auto e : v)// {// cout << e << " ";// }// cout << endl;// auto it = v.begin();// while (it != v.end())// {// // vs2019进行强制检查,erase以后认为it失效了,不能访问,访问就报错// if (*it % 2 == 0)// {// v.erase(it);// }// ++it;// }// for (auto e : v)// {// cout << e << " ";// }// cout << endl;//}void test_vector5(){//std::vector<int> v;vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(4);v.push_back(5);v.push_back(6);for (auto e : v){cout << e << " ";}cout << endl;auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}void test_vector6(){vector<string> v;v.push_back("111111111111111111111");v.push_back("111111111111111111111");v.push_back("111111111111111111111");v.push_back("111111111111111111111");v.push_back("111111111111111111111");for (auto e : v){cout << e << " ";}cout << endl;}void test_vector7(){vector<int> v1;v1.push_back(1);v1.push_back(1);v1.push_back(1);v1.push_back(1);v1.push_back(1);vector<int> v2(v1);for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}cout << endl;vector<int> v3;v3.push_back(10);v3.push_back(20);v3.push_back(30);v3.push_back(40);v1 = v3;for (auto e : v1){cout << e << " ";}cout << endl;}void test_vector8(){//vector<int> v0(10, 0);vector<string> v1(10, "xxxx");for (auto e : v1){cout << e << " ";}cout << endl;vector<int> v2;v2.push_back(10);v2.push_back(20);v2.push_back(30);v2.push_back(40);vector<int> v3(v2.begin(), v2.end());string str("hello world");vector<int> v4(str.begin(), str.end());for (auto e : v3){cout << e << " ";}cout << endl;for (auto e : v4){cout << e << " ";}cout << endl;}}