STL容器 - vector

vector概述

vector的数据存储以及操作方式和array非常相似。两者唯一的区别在于内存空间的灵活性。
array在初始化完成后就无法改变大小了;如果要扩大内存空间则必须人为申请一块新的足够大的内存,然后将原来的数据拷贝到新的地址中,最后释放原来的内存。
vector的扩容操作由其内部机制完成,当数据满了后,vector内部会申请比原来大一倍(甚至更大)的内存空间,而不是大一个元素的内存,因为“申请新内存->拷贝数据->释放旧内存”一系列操作非常耗时,所以在设计扩容机制时必须考虑减少扩容次数。

vector数据结构

vector在数据结构是一块线性连续内存空间。由两个迭代器start和finish分别指向内存中已添加元素的范围,迭代器end_of_storage指向整块内存的末尾。
下面通过代码和图例来详细介绍vector的数据结构:

vector<int> vecIn;
vecIn.push_back(1);
vecIn.push_back(2);
vecIn.push_back(3);
vecIn.push_back(4);
vecIn.push_back(5);

上面代码对应内存的状态如下:
在这里插入图片描述

vector主要接口源码剖析

因为最新版本的vector源码涉及到很多我不懂的新语法,考虑到代码可读性,下面列举的是在《STL源码剖析》一书中选用的C++2.91.57 for Windows版本的源码。

push_back()
void push_back(const T& x) {
	if (finish != end_of_storage) { // 表示备用空间够大
		construct(finish, x); // 在finish位置上执行T::T(x)操作,相当于在finish位置创建对象
		++finish;
	}
	else
		insert_aux(end(), x); // 没有备用空间可用时,需要扩容,此函数详细展开了
}
pop_back()
void pop_back() {
	--finish; // 该迭代器指向最后一个元素的起始地址
	destroy(finish); // destroy函数的本质是调用了对应类的析构函数来释放对象
}
erase()
iterator erase(iterator first, iterator last) {
	/*
	iteratpr copy(first, last, result)函数主要是将first到last的所有元素拷贝到result中
	返回值是一个迭代器,指向复制后result最后一个元素的末尾
	*/
	iterator i = copy(last, finish, first);
	destroy(i, finish); // 逐个调用析构函数释放对象
	finish = finish - (last - first);
	return first;

图示详解:
在这里插入图片描述

clear()
void clear() {
	erase(begin(), end());
}
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) {
		if (size_type(end_of_storage - finish) >= n) { // 当备用空间够大时
			T x_copy = x;
			const size_type elems_after = finish - position; // 在插入位置之后的元素个数
			iterator old_finish = finish; // 备份finish迭代器
			if (elems_after > n) { // 插入点之后的元素个数 大于 插入元素个数
				uninitialized_copy(finish - n, finish, finish);
				finish += n;
				copy_backward_copy(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;
			__STK_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();
			start = new_start;
			finish = new_finish;
			end_of_storage = new_start + len;
		}
	}
}

插入方式图示详解:

  • 插入点之后的元素个数 大于 插入元素个数
    在这里插入图片描述

  • 插入点之后的元素个数 小于等于 插入元素个数
    在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值