STL源码 vector空间配置 insert_aux 和 insert 源码
变量
iterator start; 表示目前使用空间的头
iterator finish; 表示目前使用空间的尾
iterator end_of_storage; 表示目前可用空间的尾
1.使用空间 与 可用空间(实际空间)
\;\;
start-finish维护的是使用空间,size(),即当前数组长度
\;\;
start-end_of_storage是实际空间,capacity()
\;\;
vector所采用的数据结构是线性连续空间,其实际空间总是大于等于已使用空间,一旦二者相等,整个vector需要迁移至其他空间。
\;\;
增加新元素时,如果超过当前容量(capacity),则容量会扩充至两倍(不一定2的幂次),如果仍不足,则继续扩张。需要经历“重新配置,元素移动,释放原空间”等过程。
\;\;
举个栗子:
操作 | vector元素 | size | capacity |
---|---|---|---|
vector(2,9) | 9 9 | 2 | 2 |
push_back(1) | 9 9 1 | 3 | 4 |
push_back(2) | 9 9 1 2 | 4 | 4 |
push_back(3) | 9 9 1 2 3 | 5 | 8 |
push_back(4) | 9 9 1 2 3 4 | 6 | 8 |
push_back(5) | 9 9 1 2 3 4 5 | 7 | 8 |
pop_back() | 9 9 1 2 3 4 | 6 | 8 |
pop_back() | 9 9 1 2 3 | 5 | 8 |
pop_back() | 9 9 1 2 | 4 | 8 |
find and erase 1 | 9 9 2 | 3 | 8 |
find 2 and insert(p2, 3,7) | 9 9 7 7 7 2 | 6 | 8 |
clear() | - | 0 | 8 |
2.空间配置
构造机制
\;\;
增加新元素时,如果超过当前容量(capacity),则容量会扩充至两倍,如果仍不足,则继续扩张。需要经历“重新配置,元素移动,释放原空间”等过程。
\;\;
在扩充时,使用allocate申请空间,当需要使用可用空间时,需要用construct来构造并进行赋值。
\;\;
construct内部使用了new方法,申请空间并赋值。
\;\;
allocate不会赋值,如果要使用allocate返回的内存,那么就必须先construct构造它。否则,后续的行为都是未定义的(造成的后果也是严重的)
\;\;
也就是说,在使用finish开始之后的元素时,需要特别注意,不能直接移动元素。
释放机制----
\;\; destory() 和deallocate有什么区别???
void pop_back() {
--finish; // 将尾端标记往前移一格,表示将放弃尾端元素
destory(finish);
}
例子1
vector<int>a(1,10);
vector<int>::iterator it = a.begin();
cout << (*it) << endl;
cout << "size: " << a.size() << endl;
cout << "capacity: " << a.capacity() << endl;
a.push_back(4);
cout << (*it) << endl;
cout << "size: " << a.size() << endl;
cout << "capacity: " << a.capacity() << endl;
输出:
10
size: 1
capacity: 1
8874688
size: 2
capacity: 2
开辟新空间后并整体移动,原指针指向位置不存在。
例子2 - - -
vector<int>a(5,10);
a.push_back(20);
vector<int>::iterator it = a.begin() + 5;
cout << (*it) << endl;
cout << "size: " << a.size() << endl;
cout << "capacity: " << a.capacity() << endl;
a.pop_back();
cout << a[5] << endl;
cout << (*it) << endl;
cout << "size: " << a.size() << endl;
cout << "capacity: " << a.capacity() << endl;
输出:
20
size: 6
capacity: 10
20
20
size: 5
capacity: 10
直至pop完所有元素,capacity仍然为10.
第一次pop_back()之后,a[5]仍为20,*it仍为20,都可以访问,那么destory()的作用是什么呢?
3.insert_aux源码
// 在位置position插入元素值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;
// 从position开始到原来的倒数第二位,(不包括原来的最后一位),都向后移动一位
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;
// 配置原则,如果原大小为0,则配置1(个元素大小)
// 如果原大小不为0, 则配置原大小两倍
// 前半段用来放置新数据,后半段准备用来放置新数据
iterator new_start = data_allocator::allocate(len); // 实际配置
iterator new_finish = new_start;
try{
// 将原vector内容拷贝到新vector
new_finish = uninitialized_copy(start, position, new_start);
// 为新元素设定初值x
construct(new_finish, x);
// 调整水位
++new_finish;
// 将原vector的备用空间中的内容也忠实拷贝过来(?)
new_finish = uninitialized_sopy(position, finish, new_finish);
}
catch(...) {
destory(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
// 析构并释放原vector
destory(begin(), end());
deallocate();
// 调整迭代器,指向新vector
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
4.insert源码
// 从position开始,插入n个元素,元素初值为x
template<class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, size_type n, const T &x)
{
if(n != 0) { // 当 n!=0 时,才进行以下所有操作
if(size_type(end_of_storage - finish) >= n) {
// 备用空间大于等于“新增元素个数”
T x_copy = x;
// 以下计算插入点之后的现有元素个数
const size_type elems_after = finish - position;
iterator old_finish = finish;
if(elems_after > n) {
/*
尾部的n个元素构造到finish后面去
剩余的元素向后移动
填充position开始的n个元素
*/
// "插入点之后的现有元素个数" 大于 “新增元素个数”
uninitialized_copy(finish - n, finish, finish);
finish += n; // 将vector尾端标记后移
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy); // 从插入点开始填入新值
}
else {
/*
将填充的n个元素分为两部分
从finish开始填充超过finish的部分
把position-finish的元素移到后面去
填充position-finish的部分
*/
// "插入点之后的现有元素个数" 小于等于 “新增元素个数”
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);
// 以下配置新的vector空间
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY{
// 以下首先将旧vector的插入点之前的元素复制到新空间
new_finish = uninitialized_copy(start, position, new_start);
// 以下再将新元素(初始值均为n)填入新空间
new_finish = uninitialized_copy(new_finish, n, x);
// 以下再将旧vector的插入点之后的元素复制到新空间
new_finish = uninitilized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
// 如有异常发生,实现 “commit or rollback”
destory(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
// 以下清除并释放旧的vector
destory(start, finish);
deallocate();
// 以下调整水位标记
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}