ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

SGI STL 内存基本处理工具:uninitialized_copy/uninitialized_fill/uninitialized_fill_n

2022-05-05 09:01:49  阅读:190  来源: 互联网

标签:uninitialized __ fill STL POD copy first


目录

内存基本处理工具

STL定义5个全局函数,并非空间配置器的内容,但作用于未初始化空间(空间配置器alloc配置的空间)上,对容器实现有帮助。
5个函数分别是:
1)construct()用于构造;
2)destroy()用于析构的;
3)uninitialized_copy(),对应于高层次函数std::copy();
4)uninitialized_fill(), 对应于高层次函数std::fill();
5)uninitialized_fill_n(),对应于高层次函数std::fill_n()。

1)和2)在前面一篇文章 SGI STL源码 空间配置器 中已经有讲解。本文主要讲解3)~5)。

3)到5)是低层次函数,都能让我 将内存配置与对象的构造行为分离开。如果要使用,应包含。不过,SGI把它们实际定义于<stl_unitialized>。

uninitialized_copy

uninitialized_copy() 将源迭代器区间[first, last)的每个对象拷贝到目的区间[result,...)。如果迭代器指向非POD类型,则uninitialized_copy()会调用copy constructor为输入源[first, last)的每个对象都在目的区间上产生一份复制品。

如果你要实现一个容器,uninitialized_copy() 等会为你带来很大帮助,因为容器的全区间构造函数(range constructor)通常以两个步骤完成:

  • 配置内存区块,足以包含范围内所有元素。
  • 使用uninitialized_copy(),在该内存区块上构造元素。

C++标准规格书要求uninitialized_copy() 具有“commit or rollback”语义,意思是,要么“构造出所有必要元素”,要么(当有任何一个copy constructor失败时)“不构造任何东西”。

uninitialized_copy()源码:

/**
* @brief: 将元素从源迭代器区间[first, last)拷贝到到目的迭代器区间[result,...), 内存由配置器配置alloc
* @tparam: InputIter   源区间对应的迭代器类型
* @tparam: ForwardIter 目的区间的迭代器类型
* @param first 源迭代器区间起始位置
* @param last  源迭代器区间结束位置
* @return 目的区间的结束位置对应迭代器
*/
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
  uninitialized_copy(_InputIter __first, _InputIter __last,
                     _ForwardIter __result)
{
  return __uninitialized_copy(__first, __last, __result,
                              __VALUE_TYPE(__result)); // 萃取result的value type特性, 即迭代器所指对象原生类型
}

/**
* @brief: uninitialized_copy()内部调用, 根据迭代器所指原生类型 萃取出is_POD_type特性, 转交给__uninitialized_copy_aux()处理
*/
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());  // 萃取型别Tp的is_POD_type特性, 用于判断Tp是否为POD类型
}

// Valid if copy construction is equivalent to assignment, and if the
//  destructor is trivial.
// 如果是POD型别, 就dispatch到这里.
// 迭代器所指元素是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); // 调用std::copy算法, 由于只是简单内存拷贝, 不会发生异常
}

// 如果不是POD型别, 就dispatch到这里
// 迭代器所指元素不是POD型别, 就逐个调用construct函数, 利用源区间元素来构造目的区间元素.
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);       // 调用全局construct()在cur所指内存上, 利用first构造cur所指原生类型的对象
    return __cur;
  }
  __STL_UNWIND(_Destroy(__result, __cur)); // 如果construct()调用构造函数构造对象过程抛出异常, 就析构已构造区间[result, cur)所指对象, 并且捕获异常并重新抛出.
}


// 附
#   define __STL_TRY try                                      // try 语句块
#   define __STL_UNWIND(action) catch(...) { action; throw; } // 捕获异常后先执行action, 再re-throw

template <class _Tp>
inline void _Destroy(_Tp* __pointer) { // 调用pointer所指对象的析构函数
  __pointer->~_Tp();
}

__uninitialized_copy_aux(first, last, result, __false_type)中,对“commit or rollback”的实现非常精妙:通过在迭代器所指内存上构造对象,如果抛出异常,就会终止循环并且不会正常return,而是在函数末尾通过__STL_UNWIND()不会异常,并通过_Destroy(__result, __cur)来对已经构造对象的迭代器区间[result, cur)进行析构。

POD型别

POD型别是指Plain Old Data,即标量型别(scalar types)或传统的C struct型别。参见之前这篇文章 C++ POD类型(C++ POD类型)。
一个POD类型,是指平凡的类型。而一个平凡的类或结构体符合以下定义:
1)拥有平凡的默认构造函数(trivial constructor)和析构函数(trivial destructor);

2)拥有平凡的拷贝构造函数(trivial copy constructor)和移动构造函数(trivial move constructor);

3)拥有平凡的拷贝赋值运算符(trivial assignment operator)和移动赋值运算符(trivial move operator);

4)不能包含virtual函数和virtual基类。

uninitialized_fill

如果源迭代器区间[first, last)每个迭代器都指向未初始化的内存,那么uninitialized_fill() 会在该范围内产生x(上式第三参数)的复制品。
i.e. uninitialized_fill() 会针对操作范围内的每个迭代器i,调用construct(&*i, x),在i所指之处产生x的复制品。

同uninitialized_copy(),uninitialized_fill()必须具备“commit or rollback”语义。i.e. 要么产生出所有必要元素,要么不产生任何元素。如果有任何一个copy constructor抛出异常(exception),uninitialized_fill()必须能够将已产生的所有元素析构掉。

// 要填充的迭代器区间[first, last), 要填充的值x
// 根据first所指对象value type是否为POD类型, 决定是否调用construct()构造对象
template <class _ForwardIter, class _Tp>
inline void uninitialized_fill(_ForwardIter __first,
                               _ForwardIter __last,
                               const _Tp& __x)
{
  __uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first)); // 萃取出first的value type
}

// 根据Tp1的is_POD_type特性, 将任务dispatch至不同版本的__uninitialized_fill_aux()
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; // 萃取出Tp1的is_POD_type特性
  __uninitialized_fill_aux(__first, __last, __x, _Is_POD());
                   
}

// Valid if copy construction is equivalent to assignment, and if the
// destructor is trivial.
// 如果first所指对象是POD类型, 就会dispatch至该函数
template <class _ForwardIter, class _Tp>
inline void
__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last,
                         const _Tp& __x, __true_type)
{
  fill(__first, __last, __x); // std::fill算法. 将x拷贝至目标区间[first, last). 由于是POD类型, 并未调用construct()构造对象, 不会抛出异常
}

// 如果first所指对象不是POD类型, 就会dispatch至该函数
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); // 对cur所指对象空间调用copy constructor, 以x值拷贝构造新对象
  }
  __STL_UNWIND(_Destroy(__first, __cur)); // commit or rollback 精髓: 发生异常时, 捕获异常, 析构[first, cur)所有已构造元素, 之后re-throw异常
}

uninitialized_fill_n

uninitialized_fill()以迭代器区间[first, last)的形式,让我们以x值为参数为该区间填充对象。uninitialized_fill_n()功能类似,不过提供的不是迭代器区间,而是(first, n)(迭代器起始位置,长度)的形式,可以转换为迭代器区间[first, first+n)。

uninitialized_fill_n() 也有“commit or rollback”语义:要么产生所有必要元素,否则就不产生任何元素。如果任何一个copy ctor抛出异常(exception),uninitialized_fill_n() 必须析构已产生的所有元素。

// 拷贝x值到未初始化的区域(first, n)(起始迭代器, 长度), 对应迭代器区间[first, first+n)
// 会根据first的value type, 决定是否调用construct()构造对象
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)); // 萃取出first的value type特性
}

// 根据Tp1的is_POD_type特性, dispatch至不同版本的__uninitialized_fill_n_aux()处理
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; // __type_traits<>技法, 萃取POD特性
  return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());
}

// Valid if copy construction is equivalent to assignment, and if the
//  destructor is trivial.
// 如果first所指对象是POD类型, 就会dispatch至此
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); // 将x拷贝至first为起点, 长度为n的区间
}

// 如果first所指对象不是POD类型, 就会dispatch至此
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); // 对cur所指对象空间调用copy constructor, 以x值拷贝构造新对象
    return __cur;
  }
  __STL_UNWIND(_Destroy(__first, __cur)); // commit or rollback精髓: 发生异常时, 捕获异常, 析构[first, cur)所有已构造元素, 之后re-throw异常
}

标签:uninitialized,__,fill,STL,POD,copy,first
来源: https://www.cnblogs.com/fortunely/p/16223417.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有