vector的成员变量不再是我们熟悉的size,capacity,而是变成了功能一致的三个指针:_start,_finish,_endofstorage,三个指针的作用如下:
同时,因为其本身指针的特性,其迭代器也是返回其内部的指针就可以了,因此我们可以直接定义迭代器。
大致框架如下:
namespace My
{
template
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
private:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
}
实际上,我们可以在底层初始化给三个指针都赋值为nullptr,这样默认构造就可以什么都不敢,并且在初始化时就全都赋值为nullptr,可以使代码更加简练。
代码如下:
//构造函数
vector() {
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
delete掉空间,将三个指针再次赋值为nullptr即可。
//析构
~vector() {
delete[] _start; //注意一定要加[],因为有可能存的值是一个数组
_start = _finish = _endofstorage = nullptr;
}
一般的容器,我们都有size和capacity两个函数 来获取其容器大小,在vector中我们也有这两个函数,这里我们通过 指针-指针的差值来 计算其实际值。
代码如下:
size_t size() const {
return _finish - _start;
}
代码如下:
size_t capacity() const {
return _endofstorage - _start;
}size_t capacity() const {
return _endofstorage - _start;
}
在库中,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;
}
}
resize 修改有效元素个数时,size 会进行相应的扩大或缩小变化,capacity 不一定会变化(有效元素增多时,若容量足够则capacity不变,否则会扩容;有效元素减少时,capacity 不变)
resize的两个操作如下:
- 1.如果n小于当前的size,则数据个数缩小到n
- 2.如果n大于于当前的size,则说明空间不够需要增容,并且将size扩大到n
注意,这里val得用T的默认构造。
代码示例:
//resize
void 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;
}
在指定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;
}
这里主要的就是从后往前删除的,这点需要大家注意一下。
同时,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;
}
插入尾部元素,直接复用insert.
void push_back(const T& val) {
insert(end(), val);
}
删除尾部元素,直接把_finish--就好。
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];
}
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
vector(InputIterator first, InputIterator last) {
while (first != last) {
push_back(*first);
++first;
}
}
void swap(vector& v) {
std::swap(v._start, _start);
std::swap(v._finish, _finish);
std::swap(v._endofstorage, _endofstorage);
}
//拷贝构造
vector(const vector& v) {
reserve(v.capacity());
for (auto& x : v) {
push_back(x);
}
}
//移动构造
vector(vector&& v) {
swap(v);
}
//赋值重载
vector& operator=(const vector& v) {
vector tmp(v);
swap(tmp);
return *this;
}
//移动赋值
vector& operator=(vector&& v) {
swap(v);
return *this;
}
#pragma once
#include
#include
using namespace std;
namespace My {
template
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
vector(InputIterator first, InputIterator last) {
while (first != last) {
push_back(*first);
++first;
}
}
void swap(vector& v) {
std::swap(v._start, _start);
std::swap(v._finish, _finish);
std::swap(v._endofstorage, _endofstorage);
}
//拷贝构造
vector(const vector& v) {
reserve(v.capacity());
for (auto& x : v) {
push_back(x);
}
}
//移动构造
vector(vector&& v) {
swap(v);
}
//赋值重载
vector& operator=(const vector& v) {
vector tmp(v);
swap(tmp);
return *this;
}
//移动赋值
vector& operator=(vector&& 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;
}
}
//resize
void 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 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::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 v1;
v1.resize(10);
vector 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 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::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 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 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 v;
vector 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 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 v1;
v1.push_back(1);
v1.push_back(1);
v1.push_back(1);
v1.push_back(1);
v1.push_back(1);
vector v2(v1);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
vector 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 v0(10, 0);
vector v1(10, "xxxx");
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
vector v2;
v2.push_back(10);
v2.push_back(20);
v2.push_back(30);
v2.push_back(40);
vector v3(v2.begin(), v2.end());
string str("hello world");
vector v4(str.begin(), str.end());
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
}
}