内存基本处理工具
STL定义有5个全局函数,除了前面的construct()
,destory()
,还有uninitialized_copy()、uninitialized_fill()、uninitialized_fill_n()
函数,它们三个分别应用于STL中高层次函数:copy()、fill()、fill_n()
。
uninitialized_copy
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
uninitialized_copy(_InputIter __first, _InputIter __last,
_ForwardIter __result);
uninitialized_copy()
可以将内存的配置与对象的构造行为分离开,作为输出目的地的[result,result+(last-first)]
范围内的迭代器指向未初始化的区域,uninitialized_copy()
会使用copy constructor
,将输入来源的[first,last]
范围内每一个对象的复制品放到输出范围中。
如果我们需要实现一个容器,那么这样的函数会对我们很有帮助。因为容器的全区间构造通常需要两个步骤完成:
* 配置内存区块,足以包含范围内的所有元素。
* 使用uninitialized_copy()
,在内存区块上构造函数。
我们来看看uninitialized_copy()的在SGI中的详细实现:
/**
* Name:uninitialized_copy
* Args:1.first,指向输入端的起始位置的迭代器。
* 2.last,指向输入端的结束位置的迭代器。
* 3.result,指向输入端(欲初始化空间)的起始处。
*/
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
uninitialized_copy(_InputIter __first, _InputIter __last,
_ForwardIter __result)
{
return __uninitialized_copy(__first, __last, __result,
__VALUE_TYPE(__result));
}
//首先利用_VALUE_TYPE()萃取出__result的类型,然后返回函数__uninitialized_copy(),那么__uninitialized_copy()又是怎么实现的?
/**
* Name:__uninitialized_copy
* Args:1.first,指向输入端的起始位置的迭代器。
* 2.last,指向输入端的结束位置的迭代器。
* 3.result,指向输入端(欲初始化空间)的起始处。
* 4.Tp*,已推断的类型
*/
template <class _InputIter, class _ForwardIter, class _Tp>
inline _ForwardIter
__uninitialized_copy(_InputIter __first, _InputIter __last,
_ForwardIter __result, _Tp*)
{
typedef typename __type_traits<_Tp>::is_POD_type _Is_POD; //判断_Tp是否为POD型别
return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());
}
//该函数为判断第四个参数的类型是否为POD型别,然后根据_Is_POD的返回值选择重载的函数__uninitialized_copy_aux(),下面为__uninitialized_copy_aux()的实现。
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__true_type) //如果_Is_POD返回值为true
{
return copy(__first, __last, __result); //调用copy()
}
template <class _InputIter, class _ForwardIter>
_ForwardIter
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__false_type) //如果_Is_POD返回值为false
{
_ForwardIter __cur = __result;
__STL_TRY {
for ( ; __first != __last; ++__first, ++__cur)
_Construct(&*__cur, *__first); //一个一个元素进行构造,无法批量进行
return __cur;
}
__STL_UNWIND(_Destroy(__result, __cur));
}
对于char*
和wchar*
两种类型,SGI分别设计了两种特化版本,是直接采用最具效率的memmove(直接移动内存内容)来执行复制行为:
//针对char*的特化版本
inline char* uninitialized_copy(const char* __first, const char* __last,
char* __result) {
memmove(__result, __first, __last - __first);
return __result + (__last - __first);
}
//针对wchar*的特化版本
inline wchar_t*
uninitialized_copy(const wchar_t* __first, const wchar_t* __last,
wchar_t* __result)
{
memmove(__result, __first, sizeof(wchar_t) * (__last - __first));
return __result + (__last - __first);
}
在stl_uninitialized.h
文件中还定义了uninitialized_copy_n()
,并不在C++标准库中,我们就不必研究了,有兴趣的可以去看看。
uninitialized_fill
template <class _ForwardIter, class _Tp>
inline void uninitialized_fill(_ForwardIter __first,
_ForwardIter __last,
const _Tp& __x);
uninitialized_fill()
也能够将内存配置与对象的构造行为分离开,如果[first,last]范围内的每个迭代器都指向未初始化的区域,那么uninitialized_fill()
会在该范围内填充x的复制品。
我们来看uninitialized_fill()
在SGI中的详细实现:
/**
* Name:uninitialized_fill
* Args:1.first,指向输出端的起始处的迭代器。
* 2.last,指向输出端结束处的迭代器。
* 3.x,需要设置的初值。
*/
template <class _ForwardIter, class _Tp>
inline void uninitialized_fill(_ForwardIter __first,
_ForwardIter __last,
const _Tp& __x)
{
__uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first));
}
//首先用__VALUE_TYPE()萃取__first的类型,然后传入__uninitialized_fill()中并返回该函数。下面为uninitialized_fill()的实现。
template <class _ForwardIter, class _Tp, class _Tp1>
inline void __uninitialized_fill(_ForwardIter __first,
_ForwardIter __last, const _Tp& __x, _Tp1*)
{
typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD; //判断_Tp是否为POD型别
__uninitialized_fill_aux(__first, __last, __x, _Is_POD());
}
//该函数判断传入的第四个参数的类型,然后根据根据_Is_POD返回值选择需要重载的函数。下面为__uninitialized_fill_aux()的实现。
template <class _ForwardIter, class _Tp>
inline void
__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last,
const _Tp& __x, __true_type)
{
fill(__first, __last, __x); //如果为POD类型,则调动STL中的fill()
}
template <class _ForwardIter, class _Tp>
void
__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last,
const _Tp& __x, __false_type)
{
_ForwardIter __cur = __first;
__STL_TRY {
for ( ; __cur != __last; ++__cur)
_Construct(&*__cur, __x); //如果不为POD类型,则一个一个构造,无法批量进行
}
__STL_UNWIND(_Destroy(__first, __cur));
}
uninitialized_fill_n
template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter
uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x);
uninitialized_fill_n()
也能使我们将内存配置与对象构造行为分离开,它会为指定范围内的所有元素设定相同的初值。
如果[first,last]范围内的每一个迭代器都指向未初始化的区域,那么uninitialized_fill_n()会调用copy constructor,在该范围内产生x
的复制品。
uninitialized_fill_n()
在SGI中的详细实现:
/**
* Name:uninitialized_fill_n
* Args:1.first,指向输出端的起始处的迭代器。
* 2.last,指向输出端结束处的迭代器。
* 3.x,需要设置的初值。
*/
template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter
uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x)
{
return __uninitialized_fill_n(__first, __n, __x, __VALUE_TYPE(__first));
}
//首先用__VALUE_TYPE()萃取__first的类型,然后传入__uninitialized_fill_n()并返回该函数。下面为__uninitialized_fill_n()的实现。
template <class _ForwardIter, class _Size, class _Tp, class _Tp1>
inline _ForwardIter
__uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*)
{
typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD; //判断是否为POD类型
return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());
}
//根据传入的第四个参数的类型是否为POD类型进行__uninitialized_fill_n()的重载。下面为__uninitialized_fill_n_aux()的实现。
template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter
__uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,
const _Tp& __x, __true_type)
{
return fill_n(__first, __n, __x); //如果为POD类型,则调用STL中的fill_n函数。
}
template <class _ForwardIter, class _Size, class _Tp>
_ForwardIter
__uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,
const _Tp& __x, __false_type)
{
_ForwardIter __cur = __first;
__STL_TRY {
for ( ; __n > 0; --__n, ++__cur)
_Construct(&*__cur, __x); //如果不是POD类型,则一个一个进行构造,无法进行批量处理。
return __cur;
}
__STL_UNWIND(_Destroy(__first, __cur));
}