STL定义了五个全局函数,作用于没有初始化空间上。前两个函数时用于构造的constr() 和用于析构的destroy()。另外三个是uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n(),分别对应于高层次函数copy()、fill()、fill_n()——这些都是STL算法,要使用这三个底层次函数,应该包含<memory>,不过SGI将其实现定义于<stl_uninitialized>中。
uninitialized_copy
<pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp">//如果是POD型别,执行流程会转到以下函数,这是由函数模板的参数推到机制而得
template <class _InputIter, class _ForwardIter>inline _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last, _ForwardIter __result, __true_type) // __true_type 是型别,不是变量{ // 是常规类型,可以不一个个执行拷贝构造函数 return copy(__first, __last, __result);}
<pre name="code" class="cpp"><pre name="code" class="cpp">//如果不是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 的 place new 访问方式。
_Construct(&*__cur, *__first);
return __cur;
}
//在失败时,还需要清除构建的对象,这是由 STL 标准控制
__STL_UNWIND(_Destroy(__result, __cur));
}
// 临时构建的模板函式,用来区分纯量型型别
template <class _InputIter, class _ForwardIter, class _Tp>
inline _ForwardIter
__uninitialized_copy(_InputIter __first, _InputIter __last,
_ForwardIter __result, _Tp*)
{
// 利用 type_traits 分列出数据类型,是否是 POD
// POD 意指 Plain Old Data,也就是纯量型別(scalar types)或传统的 C struct 型別。
// POD必然有构造函数、析构函数、拷贝/赋值函数,因此对POD采用最有效的初值填写法,
//对非POD采用最保险的安全方法
// POD 具有更高效率的构造方式,即直接从内存复制,而不需要拷贝构造函数。 typedef typename __type_traits<_Tp>::is_POD_type _Is_POD; // 企图利用is_POD()所获取的结果,让编译器做参数推导 return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());}// 通用式,它根据 __VALUE_TYPE 取数值类型
// 参数:first指向输入端的起始位置;
// last指向输入端的结束位置(前闭后开区间)
// 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));}// 这是特例化的,征对 char 和 wchar_t 的特例
// 这两种类型可以采取最具效率的做法memmove(直接移动内存内容)来执行复制行为。
inline char* uninitialized_copy(const char* __first, const char* __last, char* __result) { memmove(__result, __first, __last - __first); return __result + (__last - __first);}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);}
uninitialized_copy() 使我们能够将内存的配置与对象的构造行为分离开来。如果作为输出目的地的 [result, result + (last - first)) 范围内的每一个迭代器都指向未初始化区域,则 uninitialized_copy() 会使用 copy constructor,给身为输入来源之 [first, last) 范围内的每一个对象产生一份复制品,放进输出范围中。
C++标准规格书要求 uninitialized_copy() 具有 “commit or rollback” 语意,意思是要么“构造出所有必要元素”,要么(当有任何一个 copy constructor失败时)“不构造任何东西”。
uninitialized_fill
uninitialized_fill() 也能够使我们将内存配置与对象的构造行为分离开来。如果[first, last) 范围内的每个迭代器都指向未初始话的内存,那么uninitialized_fill() 会在该范围内产生 x(上式第三个参数)的复制品。换句话说,该函数会针对操作范围内的每个迭代器i,调用construct(&*i, i),在i所指之处产生x的复制品。
该函数也要具备“commit or rollback“语意,它要么产生所有必要元素,要么不产生任何元素。如果有任何一个copy constructor丢出异常,该函数必须能够将已经产生的所有元素析构掉。
// 这里是把一个集合的数据 [__first, __last) ,按 __x 值进行填充
// 这里的做法和 uninitialized_copy 一致
// Valid if copy construction is equivalent to assignment, and if the
// destructor is trivial.
<pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp">//如果是POD型别,执行流程会转到以下函数,这是由函数模板的参数推到机制而得
template <class _ForwardIter, class _Tp>inline void__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last, const _Tp& __x, __true_type){ fill(__first, __last, __x);}
<pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp">//如果不是POD型别,执行流程会转到以下函数,这是由函数模板的参数推到机制而得
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); // place new , __x 是常量的引用传递
}
__STL_UNWIND(_Destroy(__first, __cur)); // 出事了? STL 标准要求删除所有已构建的对象实例
}
<pre name="code" class="cpp">//该函数先取出first的value type,然后判断该型别是否为POD型别
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;
__uninitialized_fill_aux(__first, __last, __x, _Is_POD());
}
//uninitialized_fill()函数源码,接受三个参数:
//_first指向输出端(欲初始化空间)的起始处
//_last指向输出端(欲初始化空间)的结束处(前闭后开区间)
//_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));}
uninitialized_fill_n
uninitialized_fill_n() 能够使我们将内存配置与对象构造行为分离开来。它会为指定范围内的所有元素设定相同的初值。如果 [ first, first + n) 范围内的每一个迭代器都指向未初始化的内存,那么 uninitialized_fill_n() 会调用 copy constructor,在该范围内产生 x(上式第三个参数)的复制品。
uninitialized_fill_n() 也具有 "commit or rollback"语意。
// 这个模板填充一个集合,其成员从 [ __first, __first + n )
// 内容统一设置成 __x
// 实作技法同上
// 利用 type_traits 分列出数据类型,是否是 POD
// POD 意指 Plain Old Data,也就是纯量型別(scalar types)或传统的 C struct 型別。
// POD必然有构造函数、析构函数、拷贝/赋值函数,因此对POD采用最有效的初值填写法,
//对非POD采用最保险的安全方法
// POD 具有更高效率的构造方式,即直接从内存复制,而不需要拷贝构造函数。
<pre name="code" class="cpp">//如果拷贝构造函数等同于赋值,而且destructor是trivial,以下就有效
//如果是POD型别,执行流程会转到以下函数,这是由函数模板的参数推到机制而得
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);}
<pre name="code" class="cpp">//如果不是POD型别,执行流程会转到以下函数,这是由函数模板的参数推到机制而得
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);
return __cur;
}
__STL_UNWIND(_Destroy(__first, __cur));
}
//该函数先取出first的value type,然后判断该型别是否为POD型别
//value_type参见本系列文章《STL源码:STL迭代器》
template <class _ForwardIter, class _Size, class _Tp, class _Tp1>inline _ForwardIter __uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*){
//__type_traits技法参见本系列文章《STL源码:__type_traits》
typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD; return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());}
//该函数接受三个参数:迭代器_first指向欲初始化空间的起始处;
//_n表示欲初始化空间的大小;_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的value_type
}