一个简单的空间配置器

STl源码剖析中的一个简单空间配置器

#ifndef _JJALLOC_
#define _JJALLOC_

#include <new>
#include <cstdlib>
#include <climits>
#include <iostream>

namespace JJ {

template <typename T>
inline T* _allocate(std::ptrdiff_t size, T*) {   //为何要用ptrdiff类型,不应该有负数才对,T*的本意是用来保证空间局部性的参数,在这里并没有什么卵用
    std::set_new_handler(0);      //将set_new_handler置空,new失败时不做任何处理,直接返回nullptr
    T *tmp = (T*)(::operator new((size_t)(size * sizeof(T))));  //使用::operator new(size_t size) 分配空间
    if (!tmp) {
        std::cerr << "out of memory" << std::endl;
        std::exit(1);                                    //分配失败直接exit(1)
    }
    return tmp;
}

template <typename T>
inline void _deallocate(T* buffer) {
    ::operator delete(buffer);                   //使用::operator delete(void *) 收回分配的空间
}

template <typename T1, typename T2>
inline void _construct(T1 *p, const T2&value) {
    new(p) T1(value);        //使用placement new(void *) T(initialize) 在地址p处使用拷贝构造的方式直接构造对象
}
template <typename T>
inline void _destroy(T *ptr) {
    ptr->~T();                  //在ptr出析构对象,但不回收内存
}

template <typename T>         //符合标准接口的简单分配器
class allocator {
public:
    typedef T            value_type;
    typedef T*           pointer;
    typedef const T*     const_pointer;
    typedef T&           reference;
    typedef const T&     const_reference;
    typedef size_t       size_type;
    typedef std::ptrdiff_t    difference_type;

    template <typename U>            // 使用rebind可以得到这个模板的例外一个实例如:
    struct rebind {                     //allocator<int>::bind<string>::other stringAllocator;
        typedef allocator<U> other;     
    };                                  

    pointer allocate(size_type n, const void *hint = 0) {      //分配n个对象,hint是个提示符,需要的时候可以用来保持空间局部性
        return _allocate((difference_type)n, (pointer)0);
    }

    void deallocate(pointer p, size_type n) { _deallocate(p); }

    void construct(pointer p, const T& value) {
        _construct(p, value);
    }

    void destroy(pointer p) { _destroy(p); }

    pointer address(reference x) { return (pointer)&x; }
    const_pointer const_address(reference x) { return (const_pointer)&x; }

    size_type max_size() const {
        return size_type(UINT_MAX/sizeof(T));       //因为size_type由unsigned int实现,所以最多可以分配UINT_MAX/sizeof(T)个T对象
    }                                               //如果需要更大的空间通常使用奇怪的类型外加在硬盘分配空间
};
}

#endif // _JJALLOC_

 

看完代码,还有一些值得注意的地方:

空间配置器使用operator new与定位new分配空间并构造对象,所以可以直接使用set_new_handler(0)来指定new失败时的处理函数,然而在以malloc分配空间的地方,需要自己来实现这个机制

实际上SGI STL的空间配置器使用二级配置,并且都是使用malloc分配空间,底层使用地位new构造对象

posted on 2015-09-13 22:19  远近闻名的学渣  阅读(196)  评论(0)    收藏  举报

导航