书中对内存分配器部分。代码比较多,特别是针对小块内存的分配部分,内存分配/释放使用古老的malloc/free,代码编写在今天看来有点绕。
这里有几个思路是很值得学习的。
//2013-1-25: 补上uninitialized系列的fill,fill_n和copy函数,这三个函数和construct和destroy函数经常用于容器中。
//补上fill_n函数,没这个函数会编译错误。
#ifndef allocator_H_ #define allocator_H_ #include <new.h> #include <stddef.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <algorithm> #include <memory> #include "iterator.h" #include "type_traits.h" namespace SGISTL { //标准的STL allocator template<typename T> inline T* allocate(ptrdiff_t size) { set_new_handler(0); T* Tmep = (T*)(::operator new(size * sizeof(T))); if(Tmep == nullptr) { std::cerr<<"out of memory"<<endl; exit(1); } return Tmep; } template<typename T> inline T* allocate() { set_new_handler(0); T* Tmep = (T*)(::operator new(sizeof(T))); if(Tmep == nullptr) { std::cerr<<"out of memory"<<endl; exit(1); } return Tmep; } template<typename T> inline void deallocate(T* Buffer) { ::operator delete(Buffer); } 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 ptrdiff_t different_type; pointer allocate(size_type size) { return SGISTL::allocate<value_type>((different_type)size); } void deallocate(pointer p) { SGISTL::deallocate(p); } pointer address(reference x) { return (pointer)&x; } const_pointer address(reference x) { return (const_pointer)&x; } size_type init_page_size() { return std::max(size_type(1), size_type(4096/sizeof(T))); } size_type max_size() { return max(size_type(1), size_type(UINT_MAX/sizeof(T))); } }; /* 只使用于GCC class allocator<void> { public: typedef void* pointer; }; */ //SGI的allocator //construct and destroy template<typename T1, typename T2> inline void construct(T1* p, const T2& value) { new(p)T1(value); }; template<typename T> inline void destroy(T* p) { typedef typename type_traits<T>::has_trivial_destructor trivial_destructor; _destroy(p, trivial_destructor()); } template<typename T> inline void _destroy(T* p, false_type) { p->~T(); } template<typename T> inline void _destroy(T* p, true_type) { } template<typename ForwardIterator> inline void destroy(ForwardIterator first, ForwardIterator last) { _destroy(first, last, value_type(first)); } template<typename ForwardIterator, typename T> inline void _destroy(ForwardIterator first, ForwardIterator last, T*) { typedef type_traits<T>::has_trivial_destructor trivial_destructor; _destroy_aux(first, last, trivial_destructor()); } template<typename ForwardIterator> inline void _destroy_aux(ForwardIterator first, ForwardIterator last, false_type) { for(; first != last; ++first) { destroy(&*first); } } template<typename ForwardIterator> inline void _destroy_aux(ForwardIterator first, ForwardIterator last, true_type) { } inline void destroy(char*, char*) { } inline void destroy(wchar_t*, wchar_t*) { } //first alloc template<int inst> class __malloc_alloc_template { private: static void* oom_malloc(size_t); static void* oom_realloc(void *, size_t); static void (* __malloc_alloc_oom_handler)(); public: static void* allocate(size_t n) { void *result = malloc(n); if(result == nullptr) { result = oom_malloc(n); } return result; } static void deallocate(void *p, size_t) { free(p); } static void* reallocate(void *p, size_t, size_t new_size) { void *result = realloc(p, new_size); if(result == nullptr) { result = oom_realloc(p, new_size); } return result; } static void (* set_malloc_handler(void (*f)()))() { void (* old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = f; return (old); } }; template<int inst> void (*__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = nullptr; template<int inst> void * __malloc_alloc_template<inst>::oom_malloc(size_t n) { void (* my_malloc_handler)(); void *result; while(true) { my_malloc_handler = __malloc_alloc_oom_handler; if(my_malloc_handler == nullptr) { cerr<<"out of memory."<<endl; exit(1); } (*my_malloc_handler)(); result = malloc(n); if(result != nullptr) { return result; } } } template<int inst> void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n) { void (* my_malloc_handler)(); void *result; while(true) { my_malloc_handler = __malloc_alloc_oom_handler; if(my_malloc_handler == nullptr) { cerr<<"out of memory."<<endl; exit(1); } (*my_malloc_handler)(); result = realloc(p, n); if(result != nullptr) { return result; } } } typedef __malloc_alloc_template<0> malloc_alloc; //second alloc const size_t ALIGN = 8; const size_t MAX_BYTES = 128; const size_t NFREELISTS = MAX_BYTES / ALIGN; const size_t AMOUNTOFOBJ = 20; template<int inst> class __default_alloc_template { private: static size_t ROUND_UP(size_t n) { return ((n + ALIGN - 1) & ~(ALIGN - 1)); } private: union obj { union obj * free_list_link; char client_data[1]; }; private: static obj* volatile free_list[NFREELISTS]; static size_t FREELIST_INDEX(size_t bytes) { return ((bytes + ALIGN - 1) / ALIGN - 1); } static void* refill(size_t n); static char *chunk_alloc(size_t size, size_t &noobjs); static char *start_free; static char *end_free; static size_t heap_size; public: static void *allocate(size_t n); static void deallocate(void *p, size_t n); static void *reallocate(void *p, size_t, size_t new_size); }; template<int inst> char* __default_alloc_template<inst>::start_free = nullptr; template<int inst> char* __default_alloc_template<inst>::end_free = nullptr; template<int inst> size_t __default_alloc_template<inst>::heap_size = 0; template<int inst> typename __default_alloc_template<inst>::obj * volatile __default_alloc_template<inst>::free_list[NFREELISTS] = {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}; template<int inst> void* __default_alloc_template<inst>::allocate(size_t n) { if(n > MAX_BYTES) { return (malloc_alloc::allocate(n)); } obj * volatile * my_free_list = free_list + FREELIST_INDEX(n); obj *result = *my_free_list; if(result == nullptr) { void *r = refill(ROUND_UP(n)); return r; } else { *my_free_list = result->free_list_link; return result; } } template<int inst> void __default_alloc_template<inst>::deallocate(void *p, size_t n) { if(n > MAX_BYTES) { malloc_alloc::deallocate(p, n); } obj *q = (obj*)p; obj * volatile * my_free_list = free_list + FREELIST_INDEX(n); q->free_list_link = *my_free_list; *my_free_list = q; } template<int inst> void* __default_alloc_template<inst>::refill(size_t n) { size_t noobjs = AMOUNTOFOBJ; char * chunk = chunk_alloc(n, noobjs); if(noobjs == 1) { return chunk; } obj *result = (obj *)chunk; chunk += n; obj *current_obj = (obj *)(chunk); obj * volatile * my_freelist = free_list + FREELIST_INDEX(n); *my_freelist = current_obj; while(noobjs > 2) { chunk += n; current_obj->free_list_link = (obj *)chunk; --noobjs; } current_obj->free_list_link = nullptr; return result; } template<int inst> char* __default_alloc_template<inst>::chunk_alloc(size_t size, size_t &noobjs) { char *result; size_t total_bytes = size * noobjs; size_t bytes_left = end_free - start_free; if(bytes_left >= total_bytes)//chunk空间满足noobjs * size大小的空间 { result = start_free; start_free += total_bytes; return result; } else if(bytes_left >= size)//chunk空间只满足 大于等于size并且小于noobjs * size大小 { noobjs = bytes_left / size; total_bytes = size * noobjs; result = start_free; start_free += total_bytes; return result; } else //不能满足一个size大小 { size_t bytes_to_get = (2 * total_bytes) + ROUND_UP(heap_size * 16); if(bytes_left > 0)//chunk中有剩余空间分配给其它大小的列表 { obj * volatile * my_freelist = free_list + FREELIST_INDEX(bytes_left); ((obj *)(start_free))->free_list_link = *my_freelist; *my_freelist = (obj *)start_free; } start_free = (char *)malloc(bytes_to_get); if(start_free == nullptr) //向系统获取空间失败 { obj * volatile * my_freelist; obj *p; for(size_t i = size; i <= MAX_BYTES; i += ALIGN)//从比较自己大的空间列表里获取空间 { my_freelist = free_list + FREELIST_INDEX(i); p = *my_freelist; if(p != nullptr) { *my_freelist = p->free_list_link; start_free = (char*)p; end_free = start_free + i; return(chunk_alloc(size, noobjs)); } } end_free = 0; start_free = (char *)malloc_alloc::allocate(bytes_to_get); //最后做后努力,如果失败则退出 } heap_size += bytes_to_get; end_free = start_free + bytes_to_get; return(chunk_alloc(size, noobjs)); } } template<typename T, typename Alloc = __default_alloc_template<0>> class simple_alloc { public: static T * allocate(size_t n) { return (n == 0 ? 0 : (T*)Alloc::allocate(n * sizeof(T))); } static T * allocate(void) { return (T*)Alloc::allocate(sizeof(T)); } static void deallocate(T *p) { Alloc::deallocate(p, sizeof(T)); } static void deallocate(T *p, size_t n) { Alloc::deallocate(p, n * sizeof(T)); } }; typedef __default_alloc_template<0> alloc; //memory assistant //copy template<typename InputIterator, typename ForwardIterator> inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result) { return _uninitialized_copy(first, last, result, value_type(result)); } inline char* uninitialized_copy(char *first, char *last, char *result) { std::memmove(result, first, (last - first)); return result + (last - first); }; inline wchar_t* uninitialized_copy(wchar_t *first, wchar_t *last, wchar_t *result) { std::memmove(result, first, (last - first)); return result + (last - first); }; template<typename InputIterator, typename ForwardIterator, typename T> inline ForwardIterator _uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, T*) { typedef type_traits<T>::is_POD_type POD_type; return _uninitialized_copy_aux(first, last, result, POD_type()); }; template<typename InputIterator, typename ForwardIterator> inline ForwardIterator _uninitialized_copy_aux(InputIterator first, InputIterator last, ForwardIterator result, true_type) { return std::copy(first, last, result); } template<typename InputIterator, typename ForwardIterator> inline ForwardIterator _uninitialized_copy_aux(InputIterator first, InputIterator last, ForwardIterator result, false_type) { for(;first != last; ++first, ++result) { construct(&*result, *first); } return result; } //fill template<typename ForwardIterator, typename T> inline void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x) { _uninitialized_fill(first, last, x, value_type(first)); } template<typename ForwardIterator, typename T, typename T2> inline void _uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x, T2*) { typedef type_traits<T2>::is_POD_type POD_type; _uninitialized_fill_aux(first, last, x, POD_type()); } template<typename ForwardIterator, typename T> inline void _uninitialized_fill_aux(ForwardIterator first, ForwardIterator last, const T& x, true_type) { std::fill(first, last, x); } template<typename ForwardIterator, typename T> inline void _uninitialized_fill_aux(ForwardIterator first, ForwardIterator last, const T& x, false_type) { for(; first != last; ++first) { construct(&*first, x); } } //fill_n template<typename ForwardIterator, typename Size, typename T> inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x) { return _uninitialized_fill_n(first, n, x, value_type(first)); } template<typename ForwardIterator, typename Size, typename T, typename T2> inline ForwardIterator _uninitialized_fill_n(ForwardIterator first, Size n, const T& x, T2*) { typedef type_traits<T2>::is_POD_type POD_type; return _uninitialized_fill_n_aux(first, n, x, POD_type()); } template<typename ForwardIterator, typename Size, typename T> inline ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, true_type) { return fill_n(first, n, x); } template<typename ForwardIterator, typename Size, typename T> inline ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, false_type) { for(;n > 0; --n, ++first) { construct(&*first, x); } return first; } template<typename outputiterator, typename Size, typename T> inline outputiterator fill_n(outputiterator iter, Size n, const T& x) { for(;n >0; --n, ++iter) { *iter = x; } return iter; } } #endif