开胃菜-内存基本处理工具
<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类型调用 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有一个中央控制区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
, 值得注意的是,当总的元素个数大于桶的个数时,扩容