STL源码剖析读书笔记2

时间:2022-02-09 04:18:09

空间适配器allocator

为什么不说allocator是内存适配器而是空间适配器,原因就是你可以写
allocat直接向硬盘取空间。

allocator标准接口

STL源码剖析读书笔记2
STL源码剖析读书笔记2
STL源码剖析读书笔记2

设计一个简单的空间配置器JJ::allocator

_STD_BEGIN  
        // 这里是内存分配 
        // TEMPLATE FUNCTION _Allocate 
template<class _Ty> inline  
    _Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *)  
    {   // allocate storage for _Count elements of type _Ty 
    void *_Ptr = 0;  

    if (_Count <= 0)  
        _Count = 0;  
    else if (((_SIZT)(-1) / sizeof (_Ty) < _Count)  
        || (_Ptr = ::operator new(_Count * sizeof (_Ty))) == 0)  
        _THROW_NCEE(bad_alloc, 0);  

    return ((_Ty _FARQ *)_Ptr);  
    }  

        // 使用 placement new 进行对象的拷贝构造放置 
        // TEMPLATE FUNCTION _Construct 
template<class _Ty1,  
    class _Ty2> inline  
    void _Construct(_Ty1 _FARQ *_Ptr, _Ty2&& _Val)  
    {   // construct object at _Ptr with value _Val 
    void _FARQ *_Vptr = _Ptr;  
    ::new (_Vptr) _Ty1(_STD forward<_Ty2>(_Val));  
    }  

        // 使用 placement new 进行对象的默认构造放置 
template<class _Ty1> inline  
    void _Construct(_Ty1 _FARQ *_Ptr)  
    {   // construct object at _Ptr with default value 
    void _FARQ *_Vptr = _Ptr;  

    ::new (_Vptr) _Ty1();  
    }  

        // 对象销毁(析构函数) 
        // TEMPLATE FUNCTION _Destroy 
template<class _Ty> inline  
    void _Destroy(_Ty _FARQ *_Ptr)  
    {   // destroy object at _Ptr 
    _Ptr->~_Ty();  
    }  

        // 内嵌字符串类型不用析构,特化版本供优化使用 
template<> inline  
    void _Destroy(char _FARQ *)  
    {   // destroy a char (do nothing) 
    }  

template<> inline  
    void _Destroy(wchar_t _FARQ *)  
    {   // destroy a wchar_t (do nothing) 
    }  

 #ifdef _NATIVE_WCHAR_T_DEFINED 
template<> inline  
    void _Destroy(unsigned short _FARQ *)  
    {   // destroy a unsigned short (do nothing) 
    }  
 #endif /* _NATIVE_WCHAR_T_DEFINED */ 

        // 根据指针类型选择是否为 POD 数据类型 
        // TEMPLATE FUNCTION _Destroy_range 
template<class _Alloc> inline  
    void _Destroy_range(typename _Alloc::pointer _First,  
        typename _Alloc::pointer _Last, _Alloc& _Al)  
    {   // destroy [_First, _Last) 
    _Destroy_range(_First, _Last, _Al, _Ptr_cat(_First, _Last));  
    }  

        // 非 POD 数据类型需要显示调用析构函数 
template<class _Alloc> inline  
    void _Destroy_range(typename _Alloc::pointer _First,  
        typename _Alloc::pointer _Last, _Alloc& _Al,  
        _Nonscalar_ptr_iterator_tag)  
    {   // destroy [_First, _Last), arbitrary type 
    for (; _First != _Last; ++_First)  
        _Dest_val(_Al, _First);  
    }  

        // POD 数据类型不需要调用析构函数 
template<class _Alloc> inline  
    void _Destroy_range(typename _Alloc::pointer _First,  
        typename _Alloc::pointer _Last, _Alloc& _Al,  
        _Scalar_ptr_iterator_tag)  
    {   // destroy [_First, _Last), scalar type (do nothing) 
    }  

        // TEMPLATE FUNCTION addressof 
template<class _Ty> inline  
    _Ty * addressof(_Ty& _Val)  
    {   // return address of _Val 
    return ((_Ty *) &(char&)_Val);  
    }  

        // TEMPLATE CLASS _Allocator_base 
template<class _Ty>  
    struct _Allocator_base  
    {   // base class for generic allocators 
    typedef _Ty value_type;  
    };  

        // 偏特化,去除 const 属性 
        // TEMPLATE CLASS _Allocator_base<const _Ty> 
template<class _Ty>  
    struct _Allocator_base<const _Ty>  
    {   // base class for generic allocators for const _Ty 
    typedef _Ty value_type;  
    };  

        // TEMPLATE CLASS _ALLOCATOR 
template<class _Ty>  
    class _ALLOCATOR  
        : public _Allocator_base<_Ty>  
    {   // generic allocator for objects of class _Ty 
public:  
    typedef _Allocator_base<_Ty> _Mybase;  
    typedef typename _Mybase::value_type value_type;  

    typedef value_type _FARQ *pointer;  
    typedef value_type _FARQ& reference;  
    typedef const value_type _FARQ *const_pointer;  
    typedef const value_type _FARQ& const_reference;  

    typedef _SIZT size_type;  
    typedef _PDFT difference_type;  

    // 由于在STL容器中allocator是以模板参数传入的,而对于节点型容器,

    template<class _Other>  
        struct rebind  
        {   // convert this type to _ALLOCATOR<_Other> 
        typedef _ALLOCATOR<_Other> other;  
        };  

    pointer address(reference _Val) const  
        {   // return address of mutable _Val 
        return ((pointer) &(char&)_Val);  
        }  

    const_pointer address(const_reference _Val) const  
        {   // return address of nonmutable _Val 
        return ((const_pointer) &(char&)_Val);  
        }  

    _ALLOCATOR() _THROW0()  
        {   // construct default allocator (do nothing) 
        }  

    _ALLOCATOR(const _ALLOCATOR<_Ty>&) _THROW0()  
        {   // construct by copying (do nothing) 
        }  

    // 这里使用了 Coercion by Member Template 惯用法 
    template<class _Other>  
        _ALLOCATOR(const _ALLOCATOR<_Other>&) _THROW0()  
        {   // construct from a related allocator (do nothing) 
        }  

    // 这里使用了 Coercion by Member Template 惯用法 
    template<class _Other>  
        _ALLOCATOR<_Ty>& operator=(const _ALLOCATOR<_Other>&)  
        {   // assign from a related allocator (do nothing) 
        return (*this);  
        }  

    // 内存释放 
    void deallocate(pointer _Ptr, size_type)  
        {   // deallocate object at _Ptr, ignore size 
        ::operator delete(_Ptr);  
        }  

    // 内存分配 
    pointer allocate(size_type _Count)  
        {   // allocate array of _Count elements 
        return (_Allocate(_Count, (pointer)0));  
        }  

    pointer allocate(size_type _Count, const void _FARQ *)  
        {   // allocate array of _Count elements, ignore hint 
        return (allocate(_Count));  
        }  

    void construct(pointer _Ptr, const _Ty& _Val)  
        {   // construct object at _Ptr with value _Val 
        _Construct(_Ptr, _Val);  
        }  

    // placement new 
    void construct(pointer _Ptr, _Ty&& _Val)  
        {   // construct object at _Ptr with value _Val 
        ::new ((void _FARQ *)_Ptr) _Ty(_STD forward<_Ty>(_Val));  
        }  

    template<class _Other>  
        void construct(pointer _Ptr, _Other&& _Val)  
        {   // construct object at _Ptr with value _Val 
        ::new ((void _FARQ *)_Ptr) _Ty(_STD forward<_Other>(_Val));  
        }  

    // 对象销毁 
    void destroy(pointer _Ptr)  
        {   // destroy object at _Ptr 
        _Destroy(_Ptr);  
        }  

    _SIZT max_size() const _THROW0()  
        {   // estimate maximum array size 
        _SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);  
        return (0 < _Count ? _Count : 1);  
        }  
    };  

[1] placement new是重载operator new的一个标准、全局的版本,它不能被自定义的版本代替(不像普通的operator new和operator delete能够被替换成用户自定义的版本)。

它的原型如下:
void *operator new( size_t, void *p ) throw() { return p; }

使用方法如下:

  1. 缓冲区提前分配

可以使用堆的空间,也可以使用栈的空间,所以分配方式有如下两种:

class MyClass {…};
char *buf=new char[N*sizeof(MyClass)+ sizeof(int) ] ;
或者char buf[N*sizeof(MyClass)+ sizeof(int) ];

  1. 对象的构造

MyClass * pClass=new(buf) MyClass;

  1. 对象的销毁

一旦这个对象使用完毕,你必须显式的调用类的析构函数进行销毁对象。但此时内存空间不会被释放,以便其他的对象的构造。

pClass->~MyClass();

  1. 内存的释放

如果缓冲区在堆中,那么调用delete[] buf;进行内存的释放;如果在栈中,那么在其作用域内有效,跳出作用域,内存自动释放.

[2] size_t size=sizeof(i);//用sizeof操作得到变量i的类型的大小
ptrdiff_t diff=p2-p1;//指针的减法可以计算两个指针之间相隔的元素个数

[3]exit用在main内的时候无论main是否定义成void返回的值都是有效的,并且exit不需要考虑类型,exit⑴等价于return ⑴