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元素sizecapacity
vector(2,9)9 922
push_back(1)9 9 134
push_back(2)9 9 1 244
push_back(3)9 9 1 2 358
push_back(4)9 9 1 2 3 468
push_back(5)9 9 1 2 3 4 578
pop_back()9 9 1 2 3 468
pop_back()9 9 1 2 358
pop_back()9 9 1 248
find and erase 19 9 238
find 2 and insert(p2, 3,7)9 9 7 7 7 268
clear()-08

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;
		}		
		
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值