STL 定义又五个全局函数,作用于未初始化空间上。前两个函数是用于构造的 construct()
和用于析构的 destroy()
。另三个函数是 uninitialized_copy()
uninitialized_fill()
uninitialized_fill_n()
。
分别对应于高层次函数 copy()
fill()
fill_n()
。
template <class InputIterator, class ForwardIterator> ForwardsIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result);
uninitialized_copy()
使我们能够将内存的配置与对象的构造行为分离。对于输出范围 [result, result+(last-first))
内的未初始化区域,使用拷贝构造函数以 [first, last)
内的源对象拷贝进输出范围中。
如果你需要实现一个容器,uninitialized_copy()
会为你带来很大的帮助,因为容器的全区间**构造函数 (range constructor) **通常以两个步骤完成:
- 配置内存区块,足以包含范围内的所有元素;
- 使用
uninitialized_copy()
在该内存区块上构造元素。
Note
C++标准要求 uninitialized_copy()
具有“commit or rollback”语义,这意味这要么构造所有必要元素,要么(拷贝构造失败时)不构造任何东西。
template <class ForwardIterator, class T> void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x);
uninitialized_fill()
也使我们能够将内存配置与对象的构造行为分离。对于输出范围 [first, last)
内的未初始化区域,使用拷贝构造函数,在该范围内产生 x
的副本。
Note
C++标准同样要求 uninitialized_fill()
具有“commit or rollback”语义,这意味这要么构造所有必要元素,要么(拷贝构造失败时)不构造任何东西。如果而温暖和我一个拷贝构造函数抛出异常,uninitialized_fill()
必须能够将以构造的元素析构掉。
template <class ForwardIterator, class Size, class T> ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
uninitialized_fill_n()
也使我们能够将内存配置与对象的构造行为分离。对于输出范围 [first, first+n)
内的未初始化区域,使用拷贝构造函数,在该范围内产生 x
的副本。
Note
C++标准同样要求 uninitialized_fill_n()
具有“commit or rollback”语义,这意味这要么构造所有必要元素,要么(拷贝构造失败时)不构造任何东西。如果而温暖和我一个拷贝构造函数抛出异常,uninitialized_fill_n()
必须能够将以构造的元素析构掉。
以下分别介绍着三个函数的实现,其中所呈现的 iterator
value_type()
__type_traits
__true_type
__false_type
等实现技术都将于第三章介绍。
本函数接受三个参数
- 迭代器 first 指向欲初始化的起始处
- n 表示与初始化空间的大小
- x 表示初值
template <class ForwardIterator, class Size, class T>
inline ForwardIterator uninitialized_fill_n(ForwardIterator first,
Size n, const T& x) {
return __uninitialized_fill_n(first, n, x, value_type(first));
// 以上,利用 value_type() 取出 first 的值类型
}
这个函数首先萃取出迭代器 first 的值类型,然后判断该类型是否为 POD 类型:
template <class ForwardIterator, class Size, class T, class T1>
inline ForwardIterator __uninitialized_fill_n(ForwardIterator first,
Size n, const T& x, T1*) {
// 以下__type_traits<>技法,见 3.7
typedef typename __type_traits<T1>::is_POD_type is_POD;
return __uninitialized_fill_n_aux(first, n, x, is_POD());
}
POD 指 Plain Old Data(标量类型或传统的 C struct 类型)。POD 类型必然有平凡构造、析构、拷贝、赋值函数,因此,我们可以对 POD 类型采用最有效的初值赋值手法而对 non-POD 类型采用最保险安全的做法:
// 如果 copy constructor 等同于 assignment,而且有平凡析构,以下就有效
// 如果是 POD 类型,执行流程就会转到以下函数。这是函数模板的参数推导机制得到的
template <class ForwardIterator, class Size, class T>
inline ForwardIterator
__uninitialized_fill_n_aux(ForwardIterator first, Size n,
const T& x, __true_type) {
return fill_n(first, n, x); // 交给高阶函数执行 见 6.4.2
}
// 如果不是 POD 类型,执行流程就会转到以下函数
template <class ForwardIterator, class Size, class T>
ForwardIterator
__uninitialized_fill_n_aux(ForwardIterator first, Size n,
const T& x, __false_type) {
ForwardIterator cur = first;
// 为求阅读顺畅,以下将原本的异常处理省略
for (; n > 0; --n, ++cur)
construct(&*cur, x); // 见 2.2.3
return cur;
}
本函数接受 3 个参数:
- 迭代器 first 指向输入端的起始位置
- 迭代器 last 指向输入端的结束为止
- 迭代器 result 指向输出端的起始位置
template <class InputIterator, class ForwardIterator>
inline ForwardIterator
uninitialized_copy(InputIterator first, InputIterator last,
ForwardIterator result) {
return __uninitialized_copy(first, last, result, value_type(first));
// 以上利用 value_type() 取出 first 的值类型
}
函数首先萃取出迭代器 result 的值类型,然后判断值类型是否为 POD 类型:
template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result, T*) {
typedef typename __type_traits<T>::is_POD_type is_POD;
return __uninitialized_copy(first, last, result, is_POD());
// 以上利用 is_POD() 获得的结果让编译器做参数推导
}
如果值类型为 POD 类型,则采用最有效率的复制手法,而对 non-POD 类型采用最保险安全的做法:
// 如果 copy constructor 等同于 assignment,而且有平凡析构,以下就有效
// 如果是 POD 类型,执行流程就会转到以下函数。这是函数模板的参数推导机制得到的
template <class InputIterator, class ForwardIterator>
inline ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__true_type) {
return copy(first, last, result); // 调用 STL 算法 copy()
}
// 如果不是 POD 类型,执行流程就会转到以下函数
template <class InputIterator, class ForwardIterator>
ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__false_type) {
ForwardIterator cur = result;
// 为求阅读顺畅,以下将原本的异常处理省略
for ( ; first != last; ++first, ++cur)
construct(&*cur, *first); // 必须一个一个元素地构造,无法批量进行
return cur;
}
针对 char*
和 wchar_t*
两种类型,可以采用最具效率地做法 memmove()
来执行复制行为。因此 SGI 得以为这两种类型设计特化版本:
// const char* 特化版本
inline char* uninitialized_copy(const char* first, const char* last,
char* result) {
memmove(result, first, last - first);
return result + (last - first);
}
// const wchar_t* 特化版本
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);
}
函数接受三个参数:
- 迭代器 first 指向输出端的起始处
- 迭代器 last 指向输出端的结束处
- x 表示初值
template <class ForwardIterator, class T>
inline void uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x) {
__uninitialized_fill(first, last, x, value_type(first));
}
函数首先萃取出迭代器 first 的值类型,然后判断是否为 POD 类型:
template <class ForwardIterator, class T, class T1>
inline void __uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x, T1*) {
typedef typename __type_traits<T1>::is_POD_type is_POD;
__uninitialized_fill_aux(first, last, x, is_POD());
}
如果值类型为 POD 类型,则采用最有效率的复制手法,而对 non-POD 类型采用最保险安全的做法:
// 如果 copy constructor 等同于 assignment,而且有平凡析构,以下就有效
// 如果是 POD 类型,执行流程就会转到以下函数。这是函数模板的参数推导机制得到的
template <class ForwardIterator, class T>
void
__uninitialized_fill_aux(ForwardIterator first, ForwardIterator last,
const T& x, __true_type) {
fill(first, last, x); // 调用 STL 算法 fill()
}
// 如果不是 POD 类型,执行流程就会转到以下函数
template <class InputIterator, class ForwardIterator>
ForwardIterator
__uninitialized_fill_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__false_type) {
ForwardIterator cur = first;
// 为求阅读顺畅,以下将原本的异常处理省略
for ( ; cur != last; ++cur)
construct(&*cur, *first); // 必须一个一个元素地构造,无法批量进行
return cur;
}