本节分析vector是如何进行插入操作的,以及数组大小不足后,insert怎么来处理
insert()为了接受不同参数,定义了多个重载函数~~~
insert(iterator position, const T& x) 传入一个迭代器和插入的值
- 如果数组还有备用空间, 并且插入的是finish位置, 直接插入即可, 最后调整finish就行了.
- 以上条件不成立, 调用
insert_aux
函数执行插入操作
iterator insert(iterator position) { return insert(position, T()); }
iterator insert(iterator position, const T& x) ;
iterator insert(iterator position, const T& x)
{
size_type n = position - begin();
// 如果数组还有备用空间, 并且插入的是finish位置, 直接插入即可, 最后调整finish就行了.
if (finish != end_of_storage && position == end())
{
construct(finish, x);
++finish;
}
// 以上条件不成立, 调用另一个函数执行插入操作
else
insert_aux(position, x);
return begin() + n;
}
insert_aux:
void insert_aux(iterator position, const T& x);
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x)
{
// 如果数组还有备用空间, 就直接移动元素, 再将元素插入过去, 最后调整finish就行了.
if (finish != end_of_storage)
{
// 调用构造, 并将最后一个元素复制过去, 调整finish
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; // 重新申请空间原始空间的两倍+1的空间
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
// 进行分段将原始元素拷贝新的空间中, 这样也就实现了插入操作
new_finish = uninitialized_copy(start, position, new_start);
construct(new_finish, x);
++new_finish;
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
// 释放掉原来的空间, 调整新的3个迭代器的位置
destroy(begin(), end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
void insert (iterator pos, size_type n, const T& x) 传入一个迭代器, 插入的个数, 和插入的值
void insert (iterator pos, size_type n, const T& x);
void insert (iterator pos, int n, const T& x)
{
insert(pos, (size_type) n, x);
}
void insert (iterator pos, long n, const T& x)
{
insert(pos, (size_type) n, x);
}
如果备用空间足够大, 先保存插入位置到end的距离
1.从插入的位置到end的距离大于要插入的个数n
- 先构造出finish-n个大小的空间, 再移动finish - n个元素的数据
- 将插入位置后的n个元素移动
- 元素从插入位置开始进行填充
2.从插入的位置到end的距离小于要插入的个数
- 先构造出n - elems_after个大小的空间, 再从finish位置初始化n - elems_after为x
- 从插入位置开始到原来的finish位置结束全部复制到新的结束位置后面
- 从插入位置进行填充x
备用空间不足的时候执行
- 重新申请一个当前两倍的空间或者当前大小+插入的空间, 选择两者最大的方案.
- 进行分段复制到新的数组中, 从而实现插入
- 将当前数组的元素进行析构, 最后释放空间
- 修改3个迭代器
template <class T, class Alloc> void vector<T, Alloc>::insert(iterator position, size_type n, const T& x) { if (n != 0) { // ******** 1 *********** // 备用空间足够大 if (size_type(end_of_storage - finish) >= n) { T x_copy = x; // 保存插入位置到end的距离 const size_type elems_after = finish - position; iterator old_finish = finish; // ******* a ********** // 从插入的位置到数据结束的距离大于了要插入的个数n if (elems_after > n) { // 先构造出finish-n个大小的空间, 再移动finish - n个元素的数据 uninitialized_copy(finish - n, finish, finish); finish += n; // 在将从插入位置后的n个元素移动 copy_backward(position, old_finish - n, old_finish); // 元素从插入位置开始进行填充即可 fill(position, position + n, x_copy); } // ********* b ********* // 从插入的位置到end的距离小于了要插入的个数 else { // 先构造出n - elems_after个大小的空间, 再从finish位置初始化n - elems_after为x uninitialized_fill_n(finish, n - elems_after, x_copy); finish += n - elems_after; // 从插入位置开始到原来的finish位置结束全部复制到新的结束位置后面 uninitialized_copy(position, old_finish, finish); finish += elems_after; // 从插入位置进行填充x fill(position, old_finish, x_copy); } } // ******* 2 *********** // 空间不足处理 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; __STL_TRY { // 同样进行分段复制到新的数组中, 从而实现插入 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); } # ifdef __STL_USE_EXCEPTIONS catch(...) { destroy(new_start, new_finish); data_allocator::deallocate(new_start, len); throw; } # endif /* __STL_USE_EXCEPTIONS */ // 将当前数组的元素进行析构, 最后释放空间 destroy(start, finish); deallocate(); // 修改3个迭代器 start = new_start; finish = new_finish; end_of_storage = new_start + len; } } }
insert(iterator position, const_iterator first, const_iterator last) 传入3个迭代器
template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, const_iterator first, const_iterator last) {
// 插入不为空
if (first != last) {
size_type n = 0;
// 计算插入的长度, 并保存在n中
distance(first, last, n);
// 如果是剩余的空间大于插入的长度.
if (size_type(end_of_storage - finish) >= n) {
// 保存插入点到end的距离
const size_type elems_after = finish - position;
iterator old_finish = finish;
// 同样比较n与插入点到end的距离, 下面的过程与上面描述的基本一致.
// 从插入的位置到end的距离大于要插入的个数n
if (elems_after > n) {
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
copy(first, last, position);
}
else {
uninitialized_copy(first + elems_after, last, finish);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
copy(first, first + elems_after, position);
}
}
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;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
new_finish = uninitialized_copy(first, last, new_finish);
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
总结
vector
适合用来做随机访问很快, 也支持适合频率较低的插入和删除操作, 在每次插入和删除后迭代器都会失效, 因为不能保证操作之后迭代器的位置没有改变