zoukankan      html  css  js  c++  java
  • 自己动手实现STL 02:构造析构的基本工具construct()和destroy()(stl_construct.h)

    一、前言

      上一篇,我先完成了对内存配置器的实现。然而后面在内存上的算法还依赖于两个全局函数,construct()和destroy(),前者负责在指定的内存上调用对象的构造函数,在内存上构造出对象。后者则是相反,在指定内存上调用对象的析构函数,销毁对象。(注意:这两个函数不涉及对象内存的分配和释放,对象构造在指定的已分配好的内存上,析构也只是销毁对象,对于对象占用的那块内存,没有释放,如需释放,还需自己去free)。

    二、全局construct()函数简介

      construct(),主要功能前面已经说明,其在指定内存上构造对象。在指定内存上构造对象的功能,我们一般使用placement new。这里也是如此。construct()函数实现比较简单。实现如下:

    1 // construct()
    2 // 接受一个已分配好的内存,在其上以value为构造函数参数的来构造一个T1对象
    3 template <class T1, class T2>
    4 inline void construct(T1* p, const T2& value)
    5 {
    6     new (p) T1(value);  //placement new; 调用T1::T1(value);
    7 }

    三、全局的destroy()函数简介

      destroy()函数实现就比construct()复杂一点。这里利用了对象类型的类型属性的不同进行重载,对于不同对象的destroy都进行最适当的处理。我先把destroy()的泛化到特化的过程展示如下:

    图1:destroy()和construct()示意

    1.destroy()的第一个版本

      第一个版本只接受一个对象指针,其是对于单个对象的析构。很简单,只是调用对象本身的析构函数即可。

    1 // destroy() 第一个版本
    2 // destroy接受一个对象指针,调用该对象的析构函数
    3 // 注意:destroy函数只析构对象,没有释放其内存
    4 template <class T>
    5 inline void destroy(T* pointer)
    6 {
    7     pointer->~T(); //调用dtor ~T()
    8 }

    2.destroy()的第二版本

      对于destroy()的第二版本,他接受两个迭代器标识的一段区间,对该区间内所有对象进行析构。  

      第二版本,首先destroy()对于外部的有一个统一接口destroy()模版函数:

    1 template <class ForwardIterator>
    2 inline void destroy(ForwardIterator first, ForwardIter last)
    3 {
    4     // 利用value_type()函数提取处迭代器所指向的类型,
    5     // 并用其类型产生一个临时对象,利用编译器的类型推导,
    6     // 获取迭代器指向类型,以便后面萃取其相关属性
    7     __destroy(first, last, value_type(first));
    8 }

      其中value_type()也是一个函数模版,其主要作用是,利用编译器的类型推导,得到迭代器的类型,再利用迭代器的属性萃取类型,得到迭代器的内嵌类型value_type。并利用编译器的类型推导,在__destroy()函数中取得迭代器的value_type内嵌类型。(注:在STL的迭代器都有五个内嵌类型,其中value_Type,用于表示迭代器的指向对象的类型。同时,还有一个全局的函数value_type(),用于提取出迭代器的value_type,并用该类型生成一个该类型的指针)

    1 template <class Iterator>
    2 inline typename iterator_traits<Iterator>::value_type*
    3 value_type(const Iterator&)
    4 {
    5     // 制造一个指针类型,比制造对象用于重载效率要高
    6     return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
    7 }

      由destroy()---->__destroy()主要为了利用编译器的类型推导功能,获取迭代器的指向对象的类型value_type

    1 template <class ForwardIterator, class T>
    2 inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
    3 {
    4     // 利用__type_traits萃取处T类型的析构析构函数的否是trivial,
    5     // 并利用其has_trivial_destructor的定义类型,产生一个临时对象
    6     // 利用其进行重载
    7     typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
    8     return __destroy_aux(first, last, trivial_destructor());
    9 }

      在__destroy()函数中,又利用了用来类型属性萃取的类型__type_traits,萃取迭代器指向对象类型的一些属性。在这里,就是萃取迭代器指向对象类型对于是否有trivial析构函数的定义,并利用该定义的类型生成临时对象用于重载。

      对于has_trivial_destructor类型的具体定义的类型为__false_type(__false_type和__true_type都是类型,他们是标签类型,主要是表示一个属性是否为真。使用标签类型,主要是为了能够利用类型进行重载,这样就可以对于不同属性的结果进行不同的处理),那么说明迭代器指向类型的析构函数是non-trivail的,那么需要调用对象的析构函数。

    1 // dtor 是 non-trivial的,必须逐个调用析构函数析构
    2 template <class ForwardIterator>
    3 inline void
    4 __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
    5 {
    6     for (; first < last; ++first)
    7         destory(&*first);  //调用第一个版本,以调用析构函数
    8 }

      对于has_trivial_destructor类型的具体定义的类型为__true_type,那么迭代器指向对象类型的析构函数,其实是无用的,那么就可以不用调用了。

    1 // dtor 是trivial的,不用调用析构函数
    2 template <class ForwardIterator>
    3 inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

      最后,对于char*和wchar_t*类型的迭代器,由于char和wchar_t其都是内置类型,他们没有析构函数,也可以认为其析构是trivial的,那么就不用调用析构函数了。由于,如果采用上面的版本,还需要进行__destroy()和__destroy_aux(),这样的调用其实是无用的,因为最后什么都没有执行,为了效率的考虑,直接对第二版的destroy()函数模版进行特化。

    // 针对char*的特化版本
    
    // 对于迭代器类型是char*的,由于其char类型利用__type_traits
    // 萃取出,其应用调用__destroy_aux(ForwardIterator, ForwardIterator, __true_type)
    // 但是函数其实其实什么都没有执行,却在调用了函数,并可能产生几个临时对象,
    // 所以针对char*类型的迭代器进行特化,避免上述情况出现,提高效率
    inline void destroy(char *, char *) {}
    
    // 针对wchar_t*的特化版本
    // 原理同上
    inline void destory(wchar_t*, wchar_t*) {}

    四、stl_construct.h的完整实现源码

      如下:

     1 /*************************************************************************
     2     > File Name: stl_construct_wjzh.h
     3     > Author: wjzh
     4     > Mail: wangjzh_1@163.com 
     5     > Created Time: 2014年11月06日 星期四 14时35分29秒
     6  ************************************************************************/
     7 
     8 // 该文件中提供构造和析构的基本工具
     9 
    10 #ifndef __SGI_STL_INTERNAL_CONSTRUCT_WJZH_H
    11 #define __SGI_STL_INTERNAL_CONSTRUCT_WJZH_H 
    12 
    13 #include <new.h>
    14 
    15 __STL_BEGIN_NAMESPACE
    16 
    17 // destroy() 第一个版本
    18 // destroy接受一个对象指针,调用该对象的析构函数
    19 // 注意:destroy函数只析构对象,没有释放其内存
    20 template <class T>
    21 inline void destroy(T* pointer)
    22 {
    23     pointer->~T(); //调用dtor ~T()
    24 }
    25 
    26 // construct()
    27 // 接受一个已分配好的内存,在其上以value为构造函数参数的来构造一个T1对象
    28 template <class T1, class T2>
    29 inline void construct(T1* p, const T2& value)
    30 {
    31     new (p) T1(value);  //placement new; 调用T1::T1(value);
    32 }
    33 
    34 // destory(第二个版本实现)
    35 // 接受两个迭代器,在两个迭代器标示的区间内逐个以最适当的方式析构
    36 // 迭代器所指向的对象
    37 
    38 
    39 // dtor 是 non-trivial的,必须逐个调用析构函数析构
    40 template <class ForwardIterator>
    41 inline void
    42 __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
    43 {
    44     for (; first < last; ++first)
    45         destory(&*first);  //调用第一个版本,以调用析构函数
    46 }
    47 
    48 // dtor 是trivial的,不用调用析构函数
    49 template <class ForwardIterator>
    50 inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}
    51 
    52 template <class ForwardIterator, class T>
    53 inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
    54 {
    55     // 利用__type_traits萃取处T类型的析构析构函数的否是trivial,
    56     // 并利用其has_trivial_destructor的定义类型,产生一个临时对象
    57     // 利用其进行重载
    58     typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
    59     return __destroy_aux(first, last, trivial_destructor());
    60 }
    61 
    62 template <class ForwardIterator>
    63 inline void destroy(ForwardIterator first, ForwardIter last)
    64 {
    65     // 利用value_type()函数提取处迭代器所指向的类型,
    66     // 并用其类型产生一个临时对象,利用编译器的类型推导,
    67     // 获取迭代器指向类型,以便后面萃取其相关属性
    68     __destroy(first, last, value_type(first));
    69 }
    70 
    71 // 针对char*的特化版本
    72 
    73 // 对于迭代器类型是char*的,由于其char类型利用__type_traits
    74 // 萃取出,其应用调用__destroy_aux(ForwardIterator, ForwardIterator, __true_type)
    75 // 但是函数其实其实什么都没有执行,却在调用了函数,并可能产生几个临时对象,
    76 // 所以针对char*类型的迭代器进行特化,避免上述情况出现,提高效率
    77 inline void destroy(char *, char *) {}
    78 
    79 // 针对wchar_t*的特化版本
    80 // 原理同上
    81 inline void destory(wchar_t*, wchar_t*) {}
    82 
    83 
    84 __STL_END_NAMESPACE
    85 
    86 
    87 #endif /* __SGI_STL_INTERNAL_CONSTRUCT_WJZH_H */
    88 
    89 // End
    View Code
  • 相关阅读:
    随笔
    3.1作业
    关于JavaDate数据返回到前端变数字的问题(并引申到前后端时间的传输)
    utf-8转换为base64
    base64转换为utf-8
    Java Web基础——jsp调用动态界面
    Java Web基础——JSP指令标记
    2020软件工程最后一次作业
    软件工程第二次结对作业
    软件工程第三次作业
  • 原文地址:https://www.cnblogs.com/wangjzh/p/4105183.html
Copyright © 2011-2022 走看看