日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一个return引发的血案 - 自己动手实现allocator

發布時間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一个return引发的血案 - 自己动手实现allocator 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? 最近在追舊番《STL代碼剖析》。真的是很舊很舊的番了,STL在94年開始走入STL,這本書則是2002年出版的,C++03和C++11還不知何在的年代。看完第二章之后合上書,想自己寫一個allocator。發現看書過程中自認為“所言極是”的地方,居然根本寫不出來。雖然從前也寫過內存池 (mempool),但是STL的手法和我等閑輩果然不是一個層次。于是只好邊寫邊翻書,也算順利得寫出來了一個不支持fill和copy的版本。畢竟,stl_uninitialized相對于stl_construct和stl_alloc簡單多了,我個人也不常用它來初始化容器。

?

? ? 本來一個簡單的事情,寫完后發現malloc_alloc好用,default_alloc卻不好用,也是,memory pool自然比最naive的placement new 和 free要簡單了。檢查到最后,發現似乎alloc忘記寫return res了!加上return運行,走起!發現自己寫程序,總是寫到最后就忘記return了,果然愛旅行的人還是太年輕,總是忘記回家的路呢。

? ? (PS:需要-std_c++11哦,因為我是在受不了C98里面的尖括號問題!而且C11里的unordered_map等類的性能也比C98里的hashtable好,auto關鍵字也非常好用。)

? ? (順便回顧回顧auto_ptr、placement new、#pragma pack(n)這些最近才長的知識。)

  內存分配:

  1,大塊直接malloc和free,內存不夠時使用handler試圖產生更多內存;

  2,小塊內存使用內存池,避免因為小塊內存散落在各處,造成大量外部碎片,同時提高內存分配效率。

/*my_alloc.h */ #include <cstdlib> //for malloc and free #include "my_traits.h"#if 0 # include <new> # define __THROW_BAD_ALLOC throw bad_alloc; #else # include <iostream>using namespace std; # define __THROW_BAD_ALLOC {cerr<<"out of memory"<<endl; exit(1);}; #endif//#define __USE_MALLOC_ALLOC 0/* first level allocator */ /* __malloc_alloc_template */ template<int inst> class __malloc_alloc_template { private://out of memory//keep trying alloc until succeedstatic void* oom_alloc(size_t bytes){set_malloc_handler(0);void * res = 0;while(1){if(!__malloc_alloc_oom_handler) {__THROW_BAD_ALLOC;}(*__malloc_alloc_oom_handler)();if(res = malloc(bytes)) return res;}}static void* oom_realloc(void* p, size_t bytes){set_malloc_handler(0);void * res = 0;while(1){if(!__malloc_alloc_oom_handler) __THROW_BAD_ALLOC;(*__malloc_alloc_oom_handler)();if(res = realloc(p, bytes)) return res;}}static void (* __malloc_alloc_oom_handler)();//set the malloc handler function as fstatic void (* set_malloc_handler( void (*f)() )) (){void (*old)() = __malloc_alloc_oom_handler;__malloc_alloc_oom_handler = f;return old;} public:static void* allocate(size_t bytes){void * res = malloc(bytes);if(!res) res = oom_alloc(bytes);return res;}static void deallocate(void* p, size_t bytes){/*char * q = p;while(bytes--){free(q);q++;}*/free(p);}static void* reallocate(void* p, size_t bytes){void * res = realloc(p, bytes);if(!res) res = oom_realloc(p, bytes);return res;} }; template<int inst> void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;typedef __malloc_alloc_template<0> malloc_alloc;/* end of __malloc_alloc_template *///memory pool /* __default_alloc_template */enum {MIN_BLOCK = 8, MAX_BLOCK = 128, NFREELISTS = MAX_BLOCK/MIN_BLOCK};union obj {obj* free_list_link;char client_data[1]; };template <bool threads, int inst> class __default_alloc_template {static obj* freelist[NFREELISTS];//start of memory poolstatic char* start_free;//end of memory poolstatic char* end_free;//size of the whole memory poolstatic size_t heap_size;private://n -> 8*m//eg. 7->8, 8->8, 9->16static size_t ROUND_UP(size_t n){//n -> freelist_index//eg. 7->0, 8->0, 9->1, 16->1return (n + MIN_BLOCK - 1) & ~(MIN_BLOCK-1);}static size_t FREELIST_INDEX(size_t n){return (n/MIN_BLOCK - 1);}static char* chunk_alloc(size_t size, int & nobjs){char* res = 0;size_t bytes_needed = nobjs * size;size_t bytes_left = end_free - start_free;//if the left space meets the demand, allocate and returnif(bytes_needed <= bytes_left){res = start_free;start_free += bytes_needed;return res;}//if the left space partially meets the demand, allocateif(size <= bytes_left){res = start_free;nobjs = bytes_left/size;start_free += nobjs * size; //note that nobjs*size != bytes_leftreturn res;}//if the left space cannot meets even one block demand,size_t bytes_to_get = 2 * bytes_needed + ROUND_UP(heap_size >> 4); //bytes which are to be gained.//put the left part into the correct freelistif(bytes_left > 0){obj** my_freelist = freelist + FREELIST_INDEX(bytes_left);((obj*)(start_free))->free_list_link = *my_freelist;*my_freelist = (obj*)(start_free);}//and try to gain more space from the heap.start_free = static_cast<char*>(malloc(bytes_to_get));if(0 == start_free){int i;obj ** my_freelist;//search unused blocks in the freelist whose size le "size", and reuse it//otherwise the space in the freelist might grow huge.for(i=size; i<MAX_BLOCK; i+=MIN_BLOCK){my_freelist = freelist + FREELIST_INDEX(i);obj* p = *my_freelist;if(p){*my_freelist = p->free_list_link;start_free = (char*)(p);end_free = start_free + i;//now end_free - start_free == i >= sizereturn (chunk_alloc(size, nobjs));}}//end_free = 0; /?//turn to malloc_alloc::oom_alloc if failed.start_free = static_cast<char*>(malloc_alloc::allocate(bytes_to_get));}end_free = start_free + bytes_to_get;heap_size += bytes_to_get;return chunk_alloc(size, nobjs);}//n should be 8*mstatic void* refill(size_t n){//the default refill number of the block of size nint nobjs = 20;char* chunk = chunk_alloc(n, nobjs);obj** my_freelist = freelist + FREELIST_INDEX(n);obj* res;obj* cur;int i;//if chunk_alloc only return 1 block;if(1 == nobjs) return (chunk);//else if many blocks are chunkedres = (obj*)(chunk);*my_freelist = cur = (obj*)((char*)(res)+n);for(i=2; i<nobjs; i++){cur->free_list_link = (obj*)((char*)(cur)+n);cur = cur->free_list_link;}cur->free_list_link = 0;return res;}public:static void * allocate(size_t bytes){if(MAX_BLOCK < bytes) return malloc_alloc::allocate(bytes);//gain a space from freelistobj** my_freelist = freelist + FREELIST_INDEX(bytes);obj* res = *my_freelist;if(0 == res){return refill(ROUND_UP(bytes));}*my_freelist = res->free_list_link;return res;}static void deallocate(void* p, size_t bytes){if(MAX_BLOCK < bytes){ malloc_alloc::deallocate(p, bytes);return; }//return the deallocated space to freelist;obj** my_freelist = freelist + FREELIST_INDEX(bytes);static_cast<obj*>(p)->free_list_link = *my_freelist;*my_freelist = static_cast<obj*>(p);} };template <bool threads, int inst> char* __default_alloc_template<threads, inst>::start_free = 0; template <bool threads, int inst> char* __default_alloc_template<threads, inst>::end_free = 0; template <bool threads, int inst> size_t __default_alloc_template<threads, inst>::heap_size = 0; template <bool threads, int inst> obj * __default_alloc_template<threads, inst>::freelist[NFREELISTS]={0};/* end of __default_alloc_template */#define __NODE_ALLOCATOR_THREADS 0#ifdef __USE_MALLOC_ALLOCtypedef malloc_alloc alloc; #elsetypedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc; #endif // __USE_MALLOC/* simple_alloc */ template<class T, class Alloc=alloc> class simple_alloc { 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 difference_type; public:static T* allocate(size_t n){if(n==0) return 0;return static_cast<T*>(Alloc::allocate(n*sizeof(T)));}static const T* allocate(void){return Alloc::allocate(sizeof(T));}//釋放多個static void deallocate(T* p, size_t n){if(0!=n) Alloc::deallocate(p, n*sizeof(T));}//釋放一個static void deallocate(T* p){Alloc::deallocate(p, sizeof(T));}}; /* end of simple_alloc *//* end of my_alloc.h */

? ? ?對象構造與析構:根據type_traits進行析構(私以為構造也可如此,如int等基本類型則不必構造,直接malloc出來即可用)

? ??

/* my_constructor.h */#include <iostream> #include "my_traits.h" using namespace std;template<class T, class T1>inline void construct(T* p, const T1& value){new (p) T1(value);}template<class T>inline void destroy(T* p){typename __my_traits<T>::has_trivial_destructor a;return destroy(p, a);}template<class T>inline void destroy(T* p, __true_){cerr << "I am a trivial destructor"<<endl;}template<class T>inline void destroy(T* p, __false_){cerr << "I am not a trivial destructor."<<endl;p->~T();}template<class T>inline void destroy(T* p, T* t){typename __my_traits<T>::has_trivial_destructor a;return destroy(p, t, a);}template<class T>inline void destroy(T* f, T* t, __true_){}template<class T>inline void destroy(T* f, T* t, __false_){while(f<t){destroy(f);f++;}}inline void destroy(char *, char * p=0){}inline void destroy(wchar_t *, wchar_t * p=0){}inline void destroy(int *, int * p=0){}inline void destroy(size_t *, size_t * p=0){}inline void destroy(long long *, long long * p=0){}// .../* end of my_constructor.h*/

? ? ?類型特征萃取(type_traits):通過模板傳給traits,再通過統一的類型名稱傳遞類型信息(要求用戶類中定義好那些統一的類型名稱,并用true或false指定實際的類型)

? ? 類型特征全部用不同的數據類型表示,而不用數值(宏、枚舉等)表示:

  1,提高效率,數值需要在運行時加以判斷,而數據類型是編譯階段決定好的

? ? ?2,針對不同的類型特征,可定義重載函數而不是在同一個函數中加入if else分支,使得代碼更加清晰。

? ? type_traits最主要的作用,是使得不同類型的類得以被區別對待,避免為無作為的構造或析構付出不必要的函數調用代價。

/* my_traits.h */#ifndef __TRUE_ #define __TRUE_ struct __true_ {}; #endif // __TRUE_ #ifndef __FALSE_ #define __FALSE_ struct __false_ {}; #endif // __FALSE_#ifndef __MY_TRAITS #define __MY_TRAITS template <class _Tp> struct __my_traits {typedef __true_ this_dummy_member_must_be_first;// 不要移除這個成員// 它通知能自動特化__type_traits的編譯器, 現在這個__type_traits template是特化的// 這是為了確保萬一編譯器使用了__type_traits而與此處無任何關聯的模板時// 一切也能順利運作// 以下條款應當被遵守, 因為編譯器有可能自動生成類型的特化版本// - 你可以重新安排的成員次序// - 你可以移除你想移除的成員// - 一定不可以修改下列成員名稱, 卻沒有修改編譯器中的相應名稱// - 新加入的成員被當作一般成員, 除非編譯器提供特殊支持 typedef __false_ has_trivial_default_constructor;typedef __false_ has_trivial_copy_constructor;typedef __false_ has_trivial_assignment_operator;typedef __false_ has_trivial_destructor;typedef __false_ is_POD_type; };template <> struct __my_traits<int> {typedef __false_ has_trivial_default_constructor;typedef __false_ has_trivial_copy_constructor;typedef __false_ has_trivial_assignment_operator;typedef __false_ has_trivial_destructor;typedef __false_ is_POD_type; };#endif // __MY_TRAITS/* end of my_traits.h */

? ? ?通常為某些可以批量初始化的容器而設計的fill和copy函數,通過type_traits提取出具體的類型信息,并區別對待:

? ? ?1,對于trivial的類,只需要調用memcopy等簡單地內存函數即可;

? ? ?2,對于復雜的類,則需要調用(復制)構造函數,以避免淺復制帶來的錯誤。

? ? (部分函數體未補充完整)

/* my_uninitialized.h */#include "my_traits.h" #include <cstring>template<class T> T* uninitialized_fill(T* f, T* t, const T& x) {typename __my_traits<T>::is_POD_type a;return uninitialized_fill(f, t, x); } template<class T> T* uninitialized_fill(T* f, T* t, const T& x, __true_) { } template<class T> T* uninitialized_fill(T* f, T* t, const T& x, __false_) {}template<class T> T* uninitialized_fill_n(T* f, size_t n, const T& x) {typename __my_traits<T>::is_POD_type a;return uninitialized_fill(f, t, x, a); } template<class T> T* uninitialized_fill_n(T* f, size_t n, const T& x, __true_) {return fill_n(f, n, x); } template<class T> T* uninitialized_fill_n(T* f, size_t n, const T& x, __false_) {while(f<t){construct(f, x);f++;} }template<class T> T* uninitialized_copy(const T* srcs, const T* srcf, T* dest) { } template<class T> T* uninitialized_copy(const T* srcs, const T* srcf, T* dest, __true_) {return copy(srcs, srcf, dest); } template<class T> T* uninitialized_copy(const T* srcs, const T* srcf, T* dest, __true_) { }/* end of my_uninitialized.h */

? ? 最后試著用上面的配置器(allocator、constructor和uninitialized)寫一個簡單的vector容器:

/* vector.h */ #include <memory> #include "my_alloc.h" #include "my_construct.h"template <class T, class Alloc=alloc> class vector { public:typedef T value_type;typedef T* pointer;typedef T* iterator;typedef T& reference;typedef size_t size_type;typedef ptrdiff_t difference_type;typedef simple_alloc<T, Alloc> alloc;iterator start;iterator finish;iterator storige_end;public:vector():start(0), finish(0), storige_end(0) {}//加上explicite防止編譯器進行隱式轉換explicit vector(size_type n){start = Alloc::allocate(n);uninitialized_fill_n(start, n, T()); //此時T必須有空參數的構造函數,(否則會不會調用默認構造函數?)finish = start + n;}vector(size_type n, const T& x){start = Alloc::allocate(n);uninitialized_fill_n(start, n, T(x));finish = start + n;}vector(iterator from, iterator to){size_type len = static_cast<size_type>(to-from);start = Alloc::allocate(len);uninitialized_copy(from, to, start);finish = start + len;}~vector(){if(start){destroy(start, finish);Alloc::deallocate(start, capacity());}}const iterator begin() {return start;}const iterator end() {return finish;}size_type size() const{return static_cast<size_type>(finish - start);}size_type capacity() const{return static_cast<size_type>(storige_end - start);}bool empty() const{return start==finish;}//真的需要?void deallocate(){start && Alloc::deallocate(start, capacity());}void push_back(const T& x){insert(finish, x);}//注意,諸如fill和copy這種將數據源復制到多個變量的函數,//要考慮到所修改的內存空間是否會覆蓋到數據源所在的空間void insert(iterator pos, const T x){//空間足夠if(finish!=storige_end){construct(finish, *(finish-1));uninitialized_copy(pos, finish, pos+1);*pos = x;finish++;}else{size_type old_size = size();size_type new_size = 1;iterator new_start, new_finish;if(old_size) new_size = old_size << 1;new_start = new_finish = Alloc::allocate(new_size);//能否不用try catchtry{new_finish = uninitialized_copy(start, pos, new_start);construct(new_finish++, x);new_finish = uninitialized_copy(pos, finish, new_finish);}catch(...){if(new_start){//釋放之前真的需要析構?//需要。因為T變量中可能包含指向配置器以外的其他空間的指針。 destroy(new_start, new_finish);Alloc::deallocate(new_start, new_size);}throw;}//釋放之前真的需要析構?//需要!因為T變量中可能包含指向配置器外的其他空間的指針if(start){destroy(start, finish);//釋放 Alloc::deallocate(start, old_size);}//調整迭代器start = new_start;finish = new_finish;storige_end = new_start + new_size;}}void pop_back(){Alloc::destroy(--finish);} }; /* end of vector.h */

? ? 最后測試,用簡單類型、string類型(測試深復制)和自定義的結構體類型:

/* main.cpp */#include <iostream> #include "vector.h" #include <auto_ptr.h>/* main-my-vector.cpp*/ #pragma pack(4) struct s {int i;int j;char c;explicit s(int _i, int _j=0):i(_i), j(_j){}~s(){} }; #pragma pack()ostream & operator << (ostream & o, const s& _s) {o << "(" <<_s.i<< ", " <<_s.j<<")";return o; }main() {typedef string T;cout <<"sizeof(T) "<<sizeof(T)<<endl;auto_ptr<vector<T, simple_alloc<T>>> pv(new vector<T, simple_alloc<T>> ());vector<T, simple_alloc<T>> &v = (*pv);//vector<T, simple_alloc<T>> v;for(int i=0; i<10; i++){v.push_back(T("xx"));cout <<v.capacity()<<endl;}vector<T, simple_alloc<T>>::iterator it;for(it=v.begin(); it!=v.end(); it++)cout <<(*it)<<endl;cout <<endl; } /* end of main.cpp */

?

? ? ?看過jjhou翻譯的Effective C++系列之后,深深地變成了他的腦殘粉。本來本著閑著沒事追追星的心態去看STL代碼剖析,不到1/5的內容里,我已經被STL大師深深折服。不愧是大師,代碼寫得面面俱到,宏定義用得如火純青,光是allocator就秒殺只會寫new和delete的5星渣渣。建議和我一樣的C++新手們也去看看,看完就不是新手啦!

轉載于:https://www.cnblogs.com/zhchngzng/articles/4097436.html

總結

以上是生活随笔為你收集整理的一个return引发的血案 - 自己动手实现allocator的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日本免费网站 | 国产精品va在线观看无码 | 久久久久久久久久一级 | 国产黄色片免费看 | 天天综合欧美 | wwwxxx日本人| 日韩精品视频免费播放 | 日本一级理论片在线大全 | 国产日产欧美一区二区三区 | 撸啊撸在线视频 | 成年人香蕉视频 | 亚洲精品国产精品乱码桃花 | 人人看人人干 | 欧美一二级 | 男女男精品视频 | 毛片久久久久久 | 后宫秀女调教(高h,np) | 一区二区三区四区在线视频 | 一个人在线观看免费视频www | 99久久精品免费看国产四区 | 黄色777 | 小镇姑娘高清播放视频 | 国产一级视频在线 | 欧美视频在线免费 | 免费一区二区三区视频在线 | 蜜臀网在线 | 午夜少妇av | 亚洲91久久| 亚洲精品免费视频 | a级小视频 | 亚洲天堂成人在线 | 一眉道姑 电影 | 特大黑人巨交吊性xxxxhd | 午夜激情视频网 | 亚洲成人7777 | 中文毛片无遮挡高潮免费 | 在线观看亚洲欧美 | 亚洲图片在线播放 | 久久久久久久久久久国产 | 久久久久国产精品视频 | 午夜影院91 | 亚洲精品国产精品国自产 | 国产日韩欧美在线观看视频 | 一区二区激情视频 | 免费人成 | www在线观看国产 | 快播在线视频 | 成人黄色片免费 | 欧美日韩不卡在线 | 欧美日韩精品综合 | 亚洲女同一区 | 一本大道久久a久久精二百 琪琪色在线视频 | 中国国产毛片 | 她也啪在线视频 | 国产福利小视频在线观看 | 国产大片中文字幕 | 色图插插插 | 国产精品视频a | 夜夜操狠狠干 | a∨视频 | 少妇性高潮视频 | 少妇一晚三次一区二区三区 | 日本中文字幕不卡 | 波多野42部无码喷潮 | 黄污视频在线观看 | 成人精品免费网站 | 色奇米| 秋霞视频在线观看 | 成人午夜淫片免费观看 | 中文字幕xxxx| 精品免费囯产一区二区三区 | 国产白丝喷水 | 天堂中文在线观看 | 高潮av在线| hd丰满圆润的女人hd | 日韩高清精品免费观看 | 奇米影视久久 | 成人h动漫精品一区 | 欧美aaaaaa| 久久国产传媒 | 国产一区二区三区免费 | 免费观看日本 | 杨幂国产精品一区二区 | 亚洲天堂av线 | wwwxxxx欧美| 国产激情av一区二区三区 | 日本黄色视屏 | 男人的天堂一区 | 69精品在线 | 国产av一区二区三区传媒 | www日韩欧美 | 婷婷综合另类小说色区 | 人操人视频 | 在线观看欧美一区二区 | 国内精品视频一区二区三区 | 一区二区三区精品国产 | 私密spa按摩按到高潮 | 人人人射 | 国产亚洲在线观看 |