STL源码学习系列五: 内存处理工具(construct,destroy,uninitialized_copy,uninitialized_fill,uninitialized_fill)

内存处理工具–五个全局函数


前言

在STL中,内存处理时很关键的,特别是对于容器的实现,内存处理相当的重要。为了实现内存配置跟对象的构造行为分离开来,STL定义的五个基本全局函数,这五个全局函数中,贯穿在里面的基本上是Traits和__type_traits技术,方便内存处理,并且提高效率。有关Traits技术见前文编程技法(Traits).

STL五个全局函数(方便内存处理,并且提高效率)分别是:
construct(),destroy(),uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n();

以下分别对这些函数进行讲解。


构造基本工具:construct()

这里写图片描述
上述construct()接受一个指针p和一个初值value,该函数的用途就是将初值设定到指针所指的空间上。C++的placement new 运算子可用来完成这一任务。

 template<class T1,class T2>
 inline void construct(T1 *ptr1,const T2& value)
 {
     new(ptr1) T1(value);  //placement new 调用T1::T1(value) 在已获取内存上创建内存
 }

析构基本工具:destroy()

这里写图片描述
destroy()有两个版本,第一版本接受一个指针,准备将该指针所指之物析构掉。这很简单,直接调用该对象的析构函数即可。第二版本接受first和last两个迭代器,准备将[ first, last )范围内的所有对象析构掉(注意,这是一个左闭右开的范围)。如果范围很大,而每个对象的析构函数都无关痛痒(所谓trivial destructor),那么一次次调用这些无关痛痒的析构函数,对效率是一种伤害。因此,这里首先利用value_type()获得迭代器所指对象的型别,再利用_type_traits判断该型别的析构函数是否无关痛痒。若是(_true_type),则什么也不做就结束;若否(_false_type),这才以循环方式巡防整个范围,并在循环中每经历一个对象就调用第一个版本的destroy()。

    inline void destroy(T *ptr)
    {
        ptr->~T();   //调用 dtor ~T()
    }

    //判断元素的数值型别(valut type)是否有 trivial destructor...
    template<class ForwardIterator,class T>
    inline void destroy(ForwardIterator first, ForwardIterator last, T*)
    {
        typedef typename _type_traits<T>::has_trivial_destructor trivial_destructor;
        _destroy(first,last,trivial_destructor());
    }

    //如果元素的数值型别(valut type)有 trivial destructor...
    template<class ForwardIterator>
    inline void _destory(ForwardIterator first, ForwardIterator last, _true_type){}

    //如果元素的数值型别(valut type)有 non-trivial destructor...
    template<class ForwardIterator>
    inline void _destroy(ForwardIterator first, ForwardIterator last, _false_type)
    {
        for(;first!=last;++first)
            destroy(&*first);
    }

    template<class ForwardIterator>
    inline void destroy(ForwardIterator first, ForwardIterator last)
    {
        typedef typename _type_traits<ForwardIterator>::is_POD_type is_POD;
        _destroy(first,last,is_POD());
     }

    //针对char* wchar_t*的特化版
    inline void destroy(char*, char*){}
    inline void destroy(wchar_t*, wchar_t*){}
}

未初始化空间的复制与初始化

三个函数是uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n,分别对应于高层次函数copy()、fill()、fill_n()。

以下分别介绍这三个函数的实现法,其中所呈现的iterators(迭代器)、value_type()、_type_traits、_true_type、_false_type、is_POD_type等实现技术,见前文迭代器(Iterator).

三个内存基本函数的泛型版本与特化版本:
这里写图片描述


uninitialized_copy()

uninitialized_copy()使我们能够将内存的配置和对象的构造行为分离开来。

如果作为输出目的地的[result,result+(last-first))范围内的每一个迭代器都指向为初始化区域,则uninitialized_copy()会使用copy constructor,给身为输入来源之[first,last)范围内的每一个对象产生一份复制品,放进输出范围中。换句话说,针对输入范围内的每一个迭代器i,该函数会调用construct(&*(result+(i-first)),*i),产生*i的复制品,放置于输出范围的相对位置上。

 /*
     *未初始化的拷贝,在已获得的内存上创建一些元素
     */

    //POD标量的未初始化拷贝
    template<class InputIterator,class ForwardIterator>
    inline ForwardIterator _uninitialized_copy_aux(InputIterator first,InputIterator last,
           ForwardIterater result,_type_true)
    {
        //从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
        memcpy(result,first,(last-first)*sizeof(*first));
        return result+(last-first);
        //return copy(first,last,result); 调用STL算法copy()
    }

    //non-POD的未初始化拷贝
    template<class InputIterator,class ForwardIterator>
    ForwardIterator _uninitial_copy_aux(InputIterator first,InputIterator last,
            ForwardIterator result,_false_type)
    {
        //ForwardIterator cur=result;
        int i=0;
        for(;first!=last;++first,++i)
        {
            construct(result+i,*first);
        }
        return (result+i);
    }

    //判断该型别是否为POD型别
    template<class InputIterator,class ForwardIterator,class T>
    inline ForwardIterator _uninitiialized_copy(InputIterator first,InputIterator last,
            ForwardIterator result,T*)
    {
        typedef typename _type_traits<T>::is_POD_type isPOD;
        return _uninitialzed_copy_aux(first,last,result,isPOD()); 
        //让编译器做参数推导
    }

    template<class InputIterator,class ForwardIterator>
    inline ForwardIterator uninitialized_copy(InputIterator first,InputIterator last,
            ForwardIterator result)
    {
        return _uninitialized_copy(first,last,result,value_type(result));
        //利用value_type()萃取出first的value type
    }

    //针对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()这样的函数会为你带来很大的帮助,因为容器的全区间构造函数通常以两个步骤完成:

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

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


uninitialized_fill()

uninitialized_fill()也能够使我们将内存配置与对象的构造行为分离开来。

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

 /*
     * 未初始化的拷贝,以某一特定值初始化
     */
    template<class ForwardIterator,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value,_true_value)
    {
        fill(first,last,value);
    }

    template<class ForwardIterator,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value,_false_value)
    {
        for(;first!=last;++first)
        {
            construct(first,value);  //必须一个一个地构建
        }
    }

    template<class ForwardIterator,class T>
    inline void _uninitialized_fill(ForwardIterator first,ForwardIterator last,
            const T& value)
    {
        typedef typename _type_traits<T>::is_POD_type isPOD;
        _uninitialized_fill_aux(first,last,isPOD());
    }

    template<class ForwardIterator,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value)
    {
        _uninitialized_fill(first,last value,value_type(first));
    }

与uninitialized_copy()一样,uninitialized_fill()必须具备“commit or rollback”语意,换句话说,它要么产生出所有必要元素,要么不产生任何元素,如果有任何一个copy constructor丢出异常(exception),uninitialized_fill(),必须能够将已产生的所有元素析构掉。


uninitialized_fill_n()

uninitialized_fill_n()能使我们将内存配置与对象构造行为分离开来,它会为指定范围内的所有元素设定相同的初值。

如果[first,first+n)范围内的每一个迭代器都指向未初始化的内存,那么uninitialized_fill_n()会调用 copy constructor,在该范围内产生x(上式第三个参数——的复制品。也就是说,面对[first,first+n)范围内的每个迭代器i,uninitialized_fill_n()会调用construct(&*i,x),在对应位置产生x的复制品。

/*
     *未初始化的拷贝,以某一特定数量n初始化
     */
    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);
    }

    template<class ForwardIterator,class Size class T>
    inline ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first,Size n,
            const T& x,_false_type)
    {
       // ForwardIterator cur=result;
        int i=0;
        for(;i!=n;i++)
        {
            construct((T*)(first+i),x);
        }
        return (first+i);
    }

    template<class ForwardIterator,class Size,class T>
    inline ForwardIterator uninitialized_fill_n(ForwardIterator first,Size n,
            const T& x)
    {
        typedef typename _type_traits<T>::is_POD_type isPOD;
        _uninitialized_fill_n_aux(first,n,x,isPOD());
    }

    template<class ForwardIterator,class Size,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value)
    {
        uninitialized_fill_n(first,last value,value_type(first));
    }
}

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


总结

在这个五个全局函数中,我们可以看到,基本上是Traits和__type_traits技术的作用,方便内存处理,并且提高效率。


代码

construct.h

#ifdef _CONSTRUCT_H_
#define _CONSTRUCT_H_

#include<new>  //使用placement new
#include"typetraits.h"

namespace EasySTL
{
    template<class T1,class T2>
    inline void construct(T1 *ptr1,const T2& value)
    {
        new(ptr1) T1(value);  //placement new 调用T1::T1(value) 在已获取内存上创建内存
    }

    template<class T>
    inline void destroy(T *ptr)
    {
        ptr->~T();   //调用 dtor ~T()
    }

    //判断元素的数值型别(valut type)是否有 trivial destructor...
    template<class ForwardIterator,class T>
    inline void destroy(ForwardIterator first, ForwardIterator last, T*)
    {
        typedef typename _type_traits<T>::has_trivial_destructor trivial_destructor;
        destroy(first,last,trivial_destructor());
    }

    //如果元素的数值型别(valut type)有 trivial destructor...
    template<class ForwardIterator>
    inline void _destory(ForwardIterator first, ForwardIterator last, _true_type){}

    //如果元素的数值型别(valut type)有 non-trivial destructor...
    template<class ForwardIterator>
    inline void _destroy(ForwardIterator first, ForwardIterator last, _false_type)
    {
        for(;first!=last;++first)
            destroy(&*first);
    }

    template<class ForwardIterator>
    inline void destroy(ForwardIterator first, ForwardIterator last)
    {
        typedef typename _type_traits<ForwardIterator>::is_POD_type is_POD;
        _destroy(first,last,is_POD());
     }

    //针对char* wchar_t*的特化版
    inline void destroy(char*, char*){}
    inline void destroy(wchar_t*, wchar_t*){}
}

#endif

uninitialized.h

#ifdef _UNINITIALIZED_H_
#define _UNINITIALIZED_H_

#include"construct.h"
#include"algorithm.h"
/*
 * 将 内存配置 与 对象构造 分离开来
 */

namespace EasySTL
{
    /*
     *未初始化的拷贝,在已获得的内存上创建一些元素
     */

    //POD标量的未初始化拷贝
    template<class InputIterator,class ForwardIterator>
    inline ForwardIterator _uninitialized_copy_aux(InputIterator first,InputIterator last,
           ForwardIterater result,_type_true)
    {
        //从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
        memcpy(result,first,(last-first)*sizeof(*first));
        return result+(last-first);
        //return copy(first,last,result); 调用STL算法copy()
    }

    //non-POD的未初始化拷贝
    template<class InputIterator,class ForwardIterator>
    ForwardIterator _uninitial_copy_aux(InputIterator first,InputIterator last,
            ForwardIterator result,_false_type)
    {
        //ForwardIterator cur=result;
        int i=0;
        for(;first!=last;++first,++i)
        {
            construct(result+i,*first);
        }
        return (result+i);
    }

    //判断该型别是否为POD型别
    template<class InputIterator,class ForwardIterator,class T>
    inline ForwardIterator _uninitiialized_copy(InputIterator first,InputIterator last,
            ForwardIterator result,T*)
    {
        typedef typename _type_traits<T>::is_POD_type isPOD;
        return _uninitialzed_copy_aux(first,last,result,isPOD()); 
        //让编译器做参数推导
    }

    template<class InputIterator,class ForwardIterator>
    inline ForwardIterator uninitialized_copy(InputIterator first,InputIterator last,
            ForwardIterator result)
    {
        return _uninitialized_copy(first,last,result,value_type(result));
        //利用value_type()萃取出first的value type
    }

    //针对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);
    }

    /*
     * 未初始化的拷贝,以某一特定值初始化
     */
    template<class ForwardIterator,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value,_true_value)
    {
        fill(first,last,value);
    }

    template<class ForwardIterator,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value,_false_value)
    {
        for(;first!=last;++first)
        {
            construct(first,value);  //必须一个一个地构建
        }
    }

    template<class ForwardIterator,class T>
    inline void _uninitialized_fill(ForwardIterator first,ForwardIterator last,
            const T& value)
    {
        typedef typename _type_traits<T>::is_POD_type isPOD;
        _uninitialized_fill_aux(first,last,isPOD());
    }

    template<class ForwardIterator,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value)
    {
        _uninitialized_fill(first,last value,value_type(first));
    }

    /*
     *未初始化的拷贝,以某一特定数量n初始化
     */
    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);
    }

    template<class ForwardIterator,class Size class T>
    inline ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first,Size n,
            const T& x,_false_type)
    {
       // ForwardIterator cur=result;
        int i=0;
        for(;i!=n;i++)
        {
            construct((T*)(first+i),x);
        }
        return (first+i);
    }

    template<class ForwardIterator,class Size,class T>
    inline ForwardIterator uninitialized_fill_n(ForwardIterator first,Size n,
            const T& x)
    {
        typedef typename _type_traits<T>::is_POD_type isPOD;
        _uninitialized_fill_n_aux(first,n,x,isPOD());
    }

    template<class ForwardIterator,class Size,class T>
    inline void _uninitialized_fill_aux(ForwardIterator first,ForwardIterator last,
            const T& value)
    {
        uninitialized_fill_n(first,last value,value_type(first));
    }

}

#endif

End

猜你喜欢

转载自blog.csdn.net/qq_34777600/article/details/80437252
今日推荐