STL源码分析 # vector #
下面是一个使用vector的demo:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
/*
** To create a vector which contain 10 elements and the value
** of each element is 1
*/
vector<int> vec(10, 1);
vector<int>::iterator iter = vec.begin();
for (iter = vec.begin(); iter != vec.end(); iter++)
{
cout << *iter << endl;
}
return 0;
}
首先要知道class vector是 struct _Vector_base的衍生类.我们看看后者.
又包含一个基类struct _Vector_impl, 这里有三个指针,_M_start, _M_finish, _M_end_of_storage.
默认的初始化为0.
vector采用的数据结构非常简单,就是线性储存空间,它以两个迭代器_M_start, _M_finish分别指向配置得来的连续空间中目前已经使用的范围.并以迭代器_M_end_of_storage指向整块连续空间的尾部(包含备用空间)
_M_start 表示目前使用空间的头
_M_finish 表示目前使用空间的尾
_M_end_of_storage 表示目前可用空间的尾.
至于最后这里的不是很清楚,到现在都没找到如何在一大堆C++代码中快速的定位函数定义的位置.
我们测试一下这种内存构造布局.写个小demo:
/*
Programmer : EOF
Date : 2015.03.31
file : 4vector-test.cpp
Code description:
This is a demo to show how the vector works.
*/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int i = 0;
vector<int> iv(2, 9);
cout << "size" << iv.size() << endl; // size = 2
cout << "capacity = " << iv.capacity() << endl; // capacity = 2
iv.push_back(1);
cout << "size" << iv.size() << endl; // size = 3
cout << "capacity = " << iv.capacity() << endl; // capacity = 4
iv.push_back(2);
cout << "size" << iv.size() << endl; // size = 4
cout << "capacity = " << iv.capacity() << endl; // capacity = 4
iv.push_back(3);
cout << "size" << iv.size() << endl; // size = 5
cout << "capacity = " << iv.capacity() << endl; // capacity = 8
iv.push_back(4);
cout << "size" << iv.size() << endl; // size = 6
cout << "capacity = " << iv.capacity() << endl; // capacity = 8
for (i = 0; i < iv.size(); i++)
{
cout << iv.at(i) << ' ';
}
cout << endl;
iv.push_back(5);
cout << "size" << iv.size() << endl; // size =
cout << "capacity = " << iv.capacity() << endl; // capacity =
for (i = 0; i < iv.size(); i++)
{
cout << iv.at(i) << ' ';
}
cout << endl;
iv.pop_back();
iv.pop_back();
cout << "size" << iv.size() << endl; // size =
cout << "capacity = " << iv.capacity() << endl; // capacity =
iv.pop_back();
cout << "size" << iv.size() << endl; // size =
cout << "capacity = " << iv.capacity() << endl; // capacity =
vector<int>::iterator ivite = find(iv.begin(), iv.end(), 1);
if (ivite != iv.end())
{
iv.erase(ivite);
}
cout << "size" << iv.size() << endl; // size =
cout << "capacity = " << iv.capacity() << endl; // capacity =
for (i = 0; i < iv.size(); i++)
{
cout << iv.at(i) << ' ';
}
cout << endl;
ivite = find(iv.begin(), iv.end(), 2);
if( ivite != iv.end())
{
iv.insert(ivite, 3, 7);
}
cout << "size" << iv.size() << endl; // size =
cout << "capacity = " << iv.capacity() << endl; // capacity =
for (i = 0; i < iv.size(); i++)
{
cout << iv.at(i) << ' ';
}
cout << endl;
iv.clear();
cout << "size" << iv.size() << endl; // size =
cout << "capacity = " << iv.capacity() << endl; // capacity =
return 0;
}
size2
capacity = 2
size3
capacity = 4
size4
capacity = 4
size5
capacity = 8
size6
capacity = 8
9 9 1 2 3 4
size7
capacity = 8
9 9 1 2 3 4 5
size5
capacity = 8
size4
capacity = 8
size3
capacity = 8
9 9 2
size6
capacity = 8
9 9 7 7 7 2
size0
capacity = 8
[Finished in 0.6s]
vector用起来很像C语言的数组,但是这家伙又不是数组,而且比数组快更有效率.
而且还提供下标访问操作.
一下接口供用户访问查看当前vector占用的内存大小
值得注意的是max_size那里,好奇怪为嘛是-1...这里还不是很清楚.
这里应该是一个理论值,vector占满整个内存能装载几个_Tp类型的对象.
begin() end()返回迭代器,其实对于vector来说
我们注意到下标索引实质上是由指针运算实现的.返回引用
reference operator[](size_type __n) { return *(begin() + __n); }
const_reference operator[](size_type __n) const { return *(begin() + __n); }
和string一样!!下标索引是不安全的!!用at()函数
reference at(size_type __n)
{ _M_range_check(__n); return (*this)[__n]; }
const_reference at(size_type __n) const
{ _M_range_check(__n); return (*this)[__n]; }
vector的构造函数们~
explicit vector(const allocator_type& __a = allocator_type()) //缺省参数,构造一个空的vector
: _Base(__a) {}
vector(size_type __n, const _Tp& __value,
const allocator_type& __a = allocator_type()) //创建n个值为 __value的_Tp类型的vector
: _Base(__n, __a)
{ _M_finish = uninitialized_fill_n(_M_start, __n, __value); }
explicit vector(size_type __n)
: _Base(__n, allocator_type())
{ _M_finish = uninitialized_fill_n(_M_start, __n, _Tp()); }
vector(const vector<_Tp, _Alloc>& __x) //用别的vector初始化自己这个vector
: _Base(__x.size(), __x.get_allocator())
{ _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }
注意看析构函数,这里是调用destroy函数,从_M_start 到 _M_finish之间,而不是_M_start到_M_end_of_storage传递给destroy
~vector() { destroy(_M_start, _M_finish); }
我们常常会调用push_back把数据压入到当前vector的最后一个元素之后.
如果内存空间还富余的话(_M_finish 小于 _M_end_of_storage),利用构造函数在_M_finish处构造一个值为__x的vector元素.
如果内存空间不足了,就调用_M_insert_aux在尾部进行插入操作.push_back是没有返回值的!
很多函数都牵扯到_M_insert_aux,而这家伙的实现感觉又找不到,很奇怪...
有一个实现,但是第二个参数是bool在bvector.h里面
front() back()分别返回第一个元素的引用和最后元素的引用.
insert有各种重载,这里贴出一个
在迭代器指向的位置__position插入类型为_Tp的元素__x
erase会删除__first到__last之间的所有元素,而clear()则是调用erase删除所有元素.但是不缩减容量!!
只对_M_start, _M_end进行操作.