STL之容器源码阅读

开胃菜-内存基本处理工具

<memory> 头文件包括

  • <stl_construct.h> 定义了全局函数construct() 函数和destory() 函数,负责对象的构造和析构
  • <stl_alloc.h> 定义了一、二级配置器,配置器名为alloc
  • <stl_uninitialized.h> 定义了全局函数,用来填充(fill)或赋值(copy)大块内存数据
    uninitialized_copy() uninitialized_fill() uninitialized_fill_n()

construct() 函数
用于构造

void construct(pointer p, const T& x){
	new((void*) p) T(x);
}

destory() 函数
用于析构

void destory(pointer p){
	p->~T();
}

uninitialized_copy()

// 原型
template<class InputIterator, class ForwardIterator>
inline ForwardIterator
uninitialized_copy(InputIterator first, InputerIteraotr last,
 ForwardIterator result){
	return _uninitialized_copy(first, last, result, value_type(result));
}
template<class InputIterator, class ForwardIterator, class T>
inline ForwardIterator
_uninitialized_copy(InputIterator first, InputerIteraotr last,
ForwardIterator result, T*){
	// 萃取机萃取出类型T的POD类型
	typedef typename __type_traits<T>::is_POD_type is_POD;
	
	return _uninitialized_copy_aux(first, last, result, is_POD());
}

POD指的是Plain Old Data,指标量类型或传统C struct类型,对POD可采取有效率的复制方式,调用memcopy或memmove完成拷贝操作;对非POD类型采取逐个调用拷贝构造的方式。

何为POD类型?

POD类型调用 copy函数

// template<class InputIterator, class ForwardIterator>
// inline ForwardIterator
_uninitialized_copy_aux(InputIterator first, InputerIteraotr last,
ForwardIterator result, __true_type){
	return copy(first, last, result);
}

//  copy 内部调用 memmove函数
void * memmove(void *dest, const void *src, size_t num);

非POD类型

// template<class InputIterator, class ForwardIterator>
// inline ForwardIterator
_uninitialized_copy_aux(InputIterator first, InputerIteraotr last,
ForwardIterator result, __false_type){
	ForwardIterator cur = result;
	for(;first!=last;++first, ++cur)
		construct(&*cur, *first);
	return cur;
}

uninitialized_fill() uninitialized_fill_n() 同理

SGI vector实现

template<class T, class Alloc = alloc>
class vector{
protected:
	iterator start;    // 目前使用空间的头
	iterator finish;	// 目前使用空间的尾
	iteraotr end_of_storge; // 可用空间的尾部
public:
	void push_back(const T& x){
		if(finish!=end_of_storge){
			construct(finish, x);
			++finish;
		}
		else
			insert_aux(end(), x);
	}
}

iterator 其实就是T*;
insert_aux() 实现 如果当前可用空间不足,扩容,用try,catch实现,如果一个元素拷贝失败,实现回滚操作(commit or rollback)

void insert_aux(iterator position, const T& x){
	//  有可用空间
	if(finish!=end_of_storge){   
		... 
	}
	else{
		const size_type old_size = size();
		const size_type len = old_size + max(old_size, n);
		iterator new_start = data_alloator::allocate(len);
		iterator new_finish = new_start;
		// try尝试捕获异常
		__STL_TRY{
			// copy position 前半部分
			new_finish = uninitialized_copy(start, position, new_start);
			construct(new_finish, x);	
			++new_finish;
			// copy position 后半部分
			new_finish = uninitialized_copy(position, finish, new_finish);
		}
		// 若捕获到异常,则执行回滚操作:1.析构所有新空间的元素2.释放新空间上的内存
		catch(...){
			destory(new_start, new_finish);
			data_allocator::deallocate(new_start, len);
			throw();
		}
		// 析构、释放原来的空间
		destory(begin(), end());
		deallocate();
		
		start = new_start;
		finish = new_finish;
		end_of_storge = new_start + len;
	}
}

SGI deque实现

deque实现
让我们来看deque如何实现能够在前后都插入元素的。
看上图,deque有一个中央控制区map(默认初始化大小为8), 这个map的类型是T**,每个map中的数据为T* 指向一块连续的区域(区域大小默认512个),相邻两个map中的数据不必是连续的。
当deque初始化时,start iterator在map的居中位置,保证deque可以向两边扩展

deque如何模拟连续空间?
由迭代器实现,start和finish记录自己在map中的位置,以及buffer的当前位置,头部、尾部。当执行push_front时,start迭代器中cur == last时,将start 中的node = node - 1,并在新的buffer中插入值,完成操作

SGI hash_table实现

hash_table 由开链法实现,最重要的数据结构:vector<node*> buckets , 值得注意的是,当总的元素个数大于桶的个数时,扩容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值