Skip to content

Latest commit

 

History

History
238 lines (192 loc) · 9.81 KB

File metadata and controls

238 lines (192 loc) · 9.81 KB

2.3 内存基本处理工具

STL 定义又五个全局函数,作用于未初始化空间上。前两个函数是用于构造的 construct() 和用于析构的 destroy()。另三个函数是 uninitialized_copy() uninitialized_fill() uninitialized_fill_n()。 分别对应于高层次函数 copy() fill() fill_n()

2.3.1 uninitialized_copy()

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”语义,这意味这要么构造所有必要元素,要么(拷贝构造失败时)不构造任何东西。

2.3.2 uninitialized_fill

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() 必须能够将以构造的元素析构掉。

2.3.3 uninitialized_fill_n

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 等实现技术都将于第三章介绍。

(1) uninitialized_fill_n

本函数接受三个参数

  • 迭代器 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;
}

(2) __uninitialized_copy

本函数接受 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);
}

(3) uninitialized_fill()

函数接受三个参数:

  • 迭代器 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;
}