在STL容器的构建中,一般会使用以下几个函数来对容器的初始内存进行构建,分别是
- uninitialized_copy
- uninitialized_fill
- uninitialized_fill_n
他们定义于<stl_uninitialized.h>中, 笔记上只简单记录uninitialized_copy,其余两个函数在内容上基本相似。
uninitialized_copy
// 泛化类型
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
uninitialized_copy(_InputIter __first, _InputIter __last,
_ForwardIter __result)
uninitialized_copy 的主要作用就是将输入的一组迭代器 [first, last) 中的每一个对象都复制到[result, reuslt + (first - last))中。
源码分析
// 泛化类型
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
uninitialized_copy(_InputIter __first, _InputIter __last,
_ForwardIter __result)
{
return __uninitialized_copy(__first, __last, __result,
__VALUE_TYPE(__result));
}
// char 特化
inline char* uninitialized_copy(const char* __first, const char* __last,
char* __result) {
memmove(__result, __first, __last - __first);
return __result + (__last - __first);
}
// 泛型提取类型
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;
return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());
}
// POD类型,直接Copy
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__true_type)
{
return copy(__first, __last, __result);
}
// 非POD类型,遍历迭代器,依次构建对象
template <class _InputIter, class _ForwardIter>
_ForwardIter
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__false_type)
{
_ForwardIter __cur = __result;
__STL_TRY {
for ( ; __first != __last; ++__first, ++__cur)
_Construct(&*__cur, *__first);
return __cur;
}
__STL_UNWIND(_Destroy(__result, __cur));
}
在SGI-STL V3.3 的版本中,uninitialized_copy 有泛化版本和特化版本,如char、wchar_t等类型的调用这个函数会直接调用特化版本,然后直接使用memmove的方式对内存进行拷贝。
如果调用的是泛型版本,则会先通过__VALUE_TYPE的调用提取出迭代器所指向的对象的类型,然后再根据_Is_POD来判断对象类型是否是POD类型,是则调用std::copy函数,不是则遍历迭代器对每个对象进行拷贝构造。
其流程图基本如下:
其中,对于__VALUE_TYPE 和 _Is_POD 是如何判断类型的则先按下不表,下一章类型萃取的时候会再来回顾。