《stl源码剖析》学习笔记 1.vector

来源:互联网 发布:javascript字符串替换 编辑:程序博客网 时间:2024/06/05 07:43

1.因为vector开辟的是一段连续的堆内存,所以迭代器无需单独定义,用普通指针就行。

typedef T value_type;
typedef value_type *pointer;
typedef value_type &reference;
typedef value_type *iterator;//iterator=pointer
typedef size_t size_type;
typedef ptrdiff_t difference_type;

2.空间适配器。将alloc作为默认模板参数。

template<class T, class Alloc = alloc>
class vector

{

protected:

typedef simple_alloc<value_type, Alloc> data_allocator;

...

};

以后进行allocate和deallocate时通过data_allocator来访问就ok。

3.内存控制。因为效率因素,不能每次使用多少就开辟多少,这样的话每次使用都得经历开辟新空间,复制数据,释放原空间的过程,效率很低,有时会多开辟空间(双倍空间)所以用start,finish,end_of_storge三个指针来控制内存。start表示已开辟内存的首地址,finish表示已使用的空间末端,end_of_storge表示已开辟的内存末端(stl一般使用前闭后开的方式)。

4.构造函数。

vector(): start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T &value) { fill_initialize(n, value); }
vector(int n, const T &value) { fill_initialize(n, value); }
vector(long n, const T &value) { fill_initialize(n, value); }
explicit vector(size_type n) { fill_initialize(n, T()); }

没什么特别的,一般就这三种定义方式。

vector<int> s; vector<int> s(10, 4); vector<int> s(10);

它通过fill_initialize函数来实现分配空间,填充元素。

void fill_initialize(size_type n, const T &value)
{
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}

5.push_back(),pop_back。push_back是向末尾插入新元素,想下原理,就是判断是否还有未使用空间,如果有,那么直接在finish上构造新元素,然后++finish。

如果finish==end_of_storge了,那么开辟一段双倍的空间,然后复制原来的元素,再构造需要插入的元素,最后释放原来的空间。下次push_back时,因为刚已经开辟了多余的空间,所以直接构造新元素,移动指针就ok。  pop_back时将finish指针前移一位,然后调用析构函数。

6.erase函数。两个版本,一个是erase一个位置,另一个是erase一个区间。看代码吧。

iterator erase(iterator position)
{
if (position + 1 != end())
{

//把position+1 到finish 的数据复制到position
copy(position + 1, finish, position);
}


--finish;
destroy(finish);


return position;
}


iterator erase(iterator first, iterator last)
{

//把last到finish的数据复制到first
iterator i = copy(last, finish, first);

//析构多余的空间
destroy(i, finish);


finish = finish - (last - first);


return first;
}

7.insert函数(个人觉得这个函数写的最精妙)。


//在position位置插入n个x

void insert(iterator position, size_type n, const T &x)
{
if (n != 0)
{

//如果未使用的空间大于n,则不用另觅空间,否则得另觅空间。
if (size_type(end_of_storage - finish) >= n)
{
T x_copy = x;
const size_type elems_after = finish - position;
iterator old_finish = finish;
//
插入端到末尾的元素个数大于n情况   比如现在vector容量20,

使用10个空间,放置0 1 2 3 4 5 6 7 8 9然后在1的位置

插入5个10,elems_after  = 10-1=9,就是说从插入点到末尾有9个空间,先复制5-9到位置10开始的空间,变成012345678956789,finish=16,然后将1234复制到原来9-6的位置(从后向前复制),变成012345123456789,然后将位置1-5填充5个10.

插入端到末尾的元素个数小于n情况,比如说现在在8的位置插入5个10,elems_after=3,先在位置10到12填充3个10,0123456789 10 10 10,然后复制89,变成0123456789 10 10 10 8 9 然后在89位置填充10 得到01234567 10 10 10 10 10 8 9

if (elems_after > n)
{
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy);
}
else
{
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
}
else
{
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);


iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;


new_finish = uninitialized_copy(start, position, new_start);
new_finish = uninitialized_fill_n(new_finish, n, x);
new_finish = uninitialized_copy(position, finish,new_finish);


destroy(start, finish);
deallcate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}

}
}

原创粉丝点击