基础自实现结构
首先我们来看一看string的基础构造,有错误欢迎指正
template <class T>
class vector
{
public:
//迭代器本质上就是数据的指针
typedef T* iterator;
typedef const T* const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
// construct and destroy
vector();
vector(const vector<T>& v);
vector(int n,const T& value = T());
//别的容器的拷贝迭代器
template<class InputIterator>
vector(InpurIterator first,InputIterator);
//赋值
vector<T>& operator=(vector<T> v);
~vector();
// capacity
size_t size() const;
size_t capacity const;
void reserve(size_t n);
void resize(size_t n,const T& value = T())
///access///
T& operator[](size_t n);
const operator[](size_t n) const;
///modify/
void push_back(const T& x);
void pop_back;
void swap(vector<T>& v)
iterator insert(iterator pos,const T& x);
iterator erase(iterator pos);
private:
//这里给声明为空指针,初始化列表初始化,不然会报错
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};
1.迭代器iterator
由于vector和string不同,是用迭代器做底层实现,所以我们先写迭代器
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;
}
2.Construct and Destroy (构造和销毁)
2.1 构造,拷贝构造,析构
//构造函数不需要我们实现,但是由于我们写了拷贝函数编译器就不会自己生成了
vector() = default;
vector(const vector<T>& v)
{
reserve(v.capacity());
for(auto e :v)
{
push_back(e);
}
}
vector(int n,const T& value = T())
{
reserve(n);
while(n--)
push_back(value);
}
~vector()
{
//判空
assert(_start != nullptr)
delete[] _start;
_start = _endofstorage = _finish = nullptr;
}
2.2 =重载和inputiterator
vector<T>& operator=(vector<T>& v)
{
swap(v);
return *this;
}
template<class InputIterator>
vector(InputIterator first,InputIterator end)
{
while(first!=end)
{
push_back(*first);
++first;
}
}
3.capacity(内存)
3.1 size()和capacity()
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endofstorage - _start;
}
3.2 reserve ☆
这个可以说贯穿全文,较为重要
void reserve(size_t n)
{
if(n > capacity())
{
//创建一个old_size,防止size()造成的迭代器失效
size_t old_size = size();
T* tmp = new T[n];
memcpy(tmp,_start,size()*sizeof(T));
delete[] _start;
_start = tmp;
_finish = _start + old_size;
_endofstorage = _start + n;
}
}
3.3 resize
void resize(size_t n,const T& value = T())
{
if(n<= size())
{
_finish = _start + n;
return;
}
else
{
iterator it = _finish;
_finish = _start + n;
while(it!=_finish)
{
*it = value;
++it;
}
}
}
4.access(访问)[]符号重载
T& operator[](size_t n)
{
assert(n < size());
return *(_start + n);
}
const T& operator[](size_t n) const
{
assert(n < size());
return *(_start + n);
}
5. modify(修改)
5.1 push_back(),pop_back(),swap()
void push_back(const T& x)
{
if(size() == capacity())
{
reserve(size() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
++_finish;
}
void pop_back()
{
assert(_finish != _start);
--_finish;
}
void swap(vector<T>& v)
{
std::swap(v._start,_start);
std::swap(v._finish,_finish);
std::swap(v._endofstorage,_endofstorage);
}
5.2 insert
iterator insert(iterator pos, const T& x)
{
assert(pos <= _finish);
if(size() == capacity())
{
//start已经指向新空间,扩容要注意更新相应的pos
size_t len = pos - _start;
reserve(size() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
iterator end = _finish;
while(end != pos)
{
*end = *(end - 1);
--end;
}
*pos = x;
++_finish;
return pos;
}
5.3 erase
iterator erase(iterator pos)
{
assert(pos<size());
assert(_start != nullptr)
iterator it = pos + 1;
while(it!=_finish)
{
*(it-1) = *it;
++it;
}
--_finish;
return pos;
}
注意
个指针相减就是下标
不传参数才是默认构造
string的reserve会看情况缩容
而vector的reserve是坚决不缩容的
vector<string>用范围for要加引用:const auto& e:
operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。但at()是我们的首选,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。由于operator[]容易造成一些错误,所有我们很少用它,下面进行验证一下:
如果vector后跟的是string这种深拷贝类型,用memcpy就会导致浅拷贝报错