本部分内容包括容器vector,array和forward_list的探究。
一、vector
1. 概述
其源码如下,G2.9版本
template <class T, class Alloc = alloc>
class vector{
public:
typedef T value_type;
typedef value_type* iterator;
typedef value_type& reference;
typedef size_t size_type;
protected:
iterator start;
iterator finish;
iterator end_of_storage;
public:
iterator begin() { return start; }
iterator end() { return finish; }
size_type size() const
{ return size_type(end() - begin()); }
size_type capacity() const
{ return size_type(end_of_storage - begin()); }
bool empty() const { return begin() == end(); }
reference operator[](size_type n)
{ return *(begin() + n); }
reference front() { return *begin(); }
reference back() { return *(end() - 1); }
};
可以看到一个vector里面包含三个迭代器,vector的迭代器的类型是T*(G4.9实现得要复杂一点,但本质上还是T*)。三个迭代器分别指示元素开始位置,元素末尾位置以及容量末尾位置,所以对一个vector求sizeof的结果是12。
2. vector的扩容原理
当需要扩容时,vector会重新申请原容量两倍大小的一块内存,并把原来的元素移动到新的地址,下面以push_back()为例。
void push_back(const T& x){
if(finish != end_of_storage){
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
template<class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x){
if(finish != end_of_storage){
//在备用空间起始处构建一个元素,并以vector最后一个元素作为其初值
construct(finish, *(finish - 1));
++finish;
T x_copy = x;
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
}
else{
const size_type old_size = size();
const size_type len = old_size != 0 ? 2 * old_size : 1;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
try{
//将原vector的内容拷贝到新vector
new_finish = uninitialized_copy(start,
position, new_start);
construct(new_finish, x);
++new_finish;
//拷贝安插点后的原内容,因为这个函数也可能被insert()调用
new_finish = uninitialized_copy(position,
finish, new_finish);
}
catch(.....){
//"commit or rollback" semantics
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
//解构并释放原vector
destroy(begin(), end());
deallocate();
//调整迭代器,指向新vector
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
3. vector的迭代器
G2.9版本的vector的迭代器就是一个指针,类型为T*,所以使用iterator_traits时调用的是指针的偏特化版本。
G4.9版本的迭代器相当复杂,大概就是iterator是一种__normal_iterator<>,而__nomal_iterator<>是一个定义了五种类型的class。实际上G4.9的迭代器从根本上的类型还是T*,只不过包装得十分复杂,源码就不抄了,PPT如下:
二、array
array就是把C风格数组包装成容器的形式
1. TR1版本源码
template<typename _Tp, std::size_t _Nm>
struct array
{
typedef _Tp value_type;
typedef _Tp* pointer;
typedef value_type* iterator;
value_type _M_instance[_Nm ? _Nm : 1];
iterator begin()
{ return iterator(&_M_instance[0]); }
iterator end()
{ return iterator(&_M_instance[_Nm]); }
......
};
注意其没有构造函数和析构函数
2. G4.9版本源码
注意右上角typedef对于数组的用法,这是理解array的成员_M_elems的类型的关键。