个人主页:仍有未知等待探索-CSDN博客
专题分栏:C++
请多多指教!
目录
一、标准库中的vector
1、了解
2、vector常用接口
二、vector的实现
1、框架
2、构造、析构函数
3、操作函数
三 、问题
1、由于赋值而引起的浅拷贝
2、因为类没有实例化且用了类里面声明的类型等而产生的报错
3、内部编译器错误
一、标准库中的vector
1、了解
vector就是一个支持变长的数组。
2、vector常用接口
vector的使用不做过多强调,注重的是实现vector类。
可以点击下面的链接进入cplusplus网站,查看文档。
vector - C++ Reference
二、vector的实现
1、框架
#include <iostream>
#include <string>
#include <cstring>
#include <assert.h>
using namespace std;template<class T>
class vector
{
public:typedef T* iterator;//普通迭代器typedef const T* const_iterator;//const迭代器// Iterators: iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}// 成员函数
private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;
};
2、构造、析构函数
// 无参的构造必须写,因为下面实现了构造函数,编译器不会自动生成一个无参构造函数
vector(){}
// 开辟n个大小的空间,并初始化为m
vector(const int& n, const int& m = 0)
{// 新写法(复用reserve)reserve(n);for (int i = 0; i < n; i ++ ) _start[i] = m;_finish = _start + n;
}
// 用迭代器进行构造
template<class input_iterator>
vector(input_iterator start, input_iterator end)
{input_iterator it = start;while (it != end){push_back(*it);it ++ ;}
}
// 开辟n个大小的空间,并初始化为val
// const T& val = T() -> 用一个匿名对象进行初始化,目的是为了预防vector<T>中T是一个自定义类型。
vector(size_t n, const T& val = T())
{resize(n, val);// 复用resize
}
// 用一个vector<T>进行拷贝构造
vector(const vector<T>& v)
{reserve(v.capacity());for (auto& e : v){// 复用push_back()push_back(e);}
}
// 用列表进行初始化
// vector<int> v = {1, 2, 3};
// 用库函数实现的initializer_list<T>
vector(initializer_list<T> il)
{reserve(il.size());for (auto& e : il){push_back(e);}
}
// 析构函数
~vector()
{delete[] _start;_start = _finish = _endofstorage = nullptr;
}
3、操作函数
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}
// Capacity:
size_t capacity() const
{return _endofstorage - _start;
}
size_t size() const
{return _finish - _start;
}
bool empty() const
{return size() == 0;
}
void reserve(size_t n)
{if (capacity() < n){T* tmp = new T[n];int old_size = size();//memcpy(tmp, _start, size() * sizeof(T));// 当T是string类型的时候,memcpy会导致浅拷贝问题,并且会同时对一块空间析构多次for (int i = 0; i < old_size; i ++ ){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + n;}
}
void resize(size_t n, const T& val = T())
{reserve(n);iterator it = _start;while (it != _endofstorage){*it = val;it ++ ;}
}
// Element access:
T& operator[](int pos)
{assert(pos < size());return _start[pos];
}// Modifiers:
// 在pos之前插入一个数x
void insert(iterator pos, const T& x)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){int len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}iterator it = _finish - 1;while (it >= pos) {*(it + 1) = *it;it -- ;}*pos = x;_finish ++ ;
}
// 尾插
void push_back(const T& x)
{// 老写法/*if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;_finish ++ ;*/// 新写法insert(end() , x);
}
// 尾删
void pop_back()
{assert(!empty());_finish -- ;
}
// 交换函数,用库里面的swap实现指针的交换,来完成vector的交换
void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);
}
三 、问题
1、由于赋值而引起的浅拷贝
如果要将一个引用进行赋值,并且没有对赋值运算符重载的话,会只进行值拷贝而导致浅拷贝。最后会使编译器对同一块空间析构多次。
为什么*pos,x都是T类型的,而赋值重载却写一个vector<T>类型的就能行?
因为单参数的构造函数支持隐式类型转化,编译器会先进行构造函数,将这两个值构造成对象,然后在进行赋值。
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}
2、因为类没有实例化且用了类里面声明的类型等而产生的报错
需要在使用这个类型前面加上typename标志这是一个类型。
template<class T>
void print_vector(vector<T>& v)
{// 不加typename会报错,因为在这个函数模板里,vector<T>这个类并没有实例化,会不清楚const_iterator是类型还是变量// 加typename的含义就是告诉编译器,这个是类型typename vector<T>::const_iterator it = v.begin();//auto it = v.begin();while (it != v.end()){cout << *it << " ";it ++ ;}
}
3、内部编译器错误
这个错误的原因是类模板或函数模板里面有语法错误。(比如说少加了一个分号等等)