vector
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:
typedef simple_alloc<value_type, Alloc> data_allocator;//simple_alloc是
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的迭代器类型为value_type*,即T*。相比于list中的迭代器声明一个新的类要简单,这是因为vector为分配的顺序结构,不需要定义节点前后指针。
- vector中包含三个迭代器,分别指向元素开始位置,元素末尾位置(前闭后开),容器末尾位置。
- vetcor的大小为其成员即三个指针的大小sizeof(vector< T>)=12
vector扩容原理
当vector进行push_back()或insert()操作时,若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-1位置的元素挪到finsh
++finish;//finish后退
T x_copy = x;
copy_backward(position, finish - 2, finish - 1);//将pos到finish-2处元素全部往后退
*position = x_copy;//将待插入的元素插入position
}
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;
}
}
其中的construct和destroy源自allocator,可被全局调用,源码如下
// 自定义空间配置器
template<typename T>
struct myallocator
{
// 开辟内存空间
T* allocate(size_t size)
{
return (T*)::operator new(sizeof(T)*size);// 相当于malloc分配内存
}
// 释放内存空间
void deallocate(void *ptr, size_t size)
{
::operator delete(ptr, sizeof(T)*size);// 相当于free释放内存
}
// 负责对象构造
void construct(T *ptr, const T &val)
{
new ((void*)ptr) T(val);// 用定位new在指定内存上构造对象
}
// 负责对象析构
void destroy(T *ptr)
{
ptr->~T();// 显示调用对象的析构函数
}
};
四个函数作用如下:
vector的iterator
既然vector是连续空间,其iterator可以不用设计成为一个class,将指针作为其迭代器 。
在G2.9版本中,当iterator对象放入iterator_traits中,被识别为T*的native pointer偏特化版本。
在G4.9版本中,iterator是一种_normal_iterator<>,他是一种定义了五种iterator基本类型的class,而_normal_iterator<>中包含继承自_Vector_base<>中的指针成员,这个指针成员由继承自_alloc_traits<>,根本类型上还是T *。
在4.9版中iterator对象放入iterator-traits被识别为class版本
array
G2.9版本
把C风格数组包装为容器形式
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]); }
......
};
- 定义一个类型为value_type的_M_instance数组,以Nm为总大小,当Nm为0时,自动生成大小为1的数组
- begin()指向数组第0个,end()指向数组第最后一个元素(前开后闭)
- array没有ctro和dtor
- array也是连续空间,其iterater也是native pointer,交给iterator_traits时调用T*的版本
使用array时要指定大小
array<int, 10> myArray;
auto ite = myArray.begin();
G4.9版本
在typedef用法中,将_Type指代为_Tp[_Nm]的数组,并在函数传入参数时直接使用_Type类型数组_M_elems。