怎么有效的手撕代碼呢?
gnu gcc 2.9 的 內存池
- 把代碼跑起來
- 把代碼一個片段拿出來使用
- 畫出代碼運行的流程圖
- 一行一行的搬運
- 在看源碼的情況下寫出類似的demo
第三步:
第五步:
// 這個頭文件包含一個模板類 allocator,用于管理內存的分配、釋放,對象的構造、析構
//TODO: debug
/*全大寫為 define const enum
成員變量 M開頭
全局變量 G開頭
static S開頭
內部使用 “__”開頭為內部(私有)函數變量或者同名的包函數 “_”為其他的一般內部部分 注變量常為“__”*/
#pragma once#include <new> // for placement new
#include <cstddef> // for ptrdiff_t size_t
#include <cstdlib> // for exit
#include <climits> // for UINT_MAX
#include <iostream> // for cerrenum { ALIGN = 8 };
enum { MAX_BYTES = 128 };
enum { NFREELISTS = MAX_BYTES / ALIGN };#define FREE_INDEX(args) (args/ALIGN -1)
#define UP_ROUND(args) ((args+ALIGN-1)& ~(ALIGN -1))#if 0
# include <new>
# define __THROW_BAD_ALLOC throw bad_alloc()
#elif !defined(__THROW_BAD_ALLOC)
# include <iostream>
# define __THROW_BAD_ALLOC cerr << "out of memory" << endl; exit(1)
#endifnamespace kstd
{/*new 處理函數set_new_handler()是為分配函數在凡是內存分配嘗試失敗時調用的函數。其目的是三件事之一:1) 令更多內存可用2) 終止程序(例如通過調用 std::terminate3) 拋出 std::bad_alloc 或自 std::bad_alloc 導出的類型的異常。*///創建內存template <class T>inline T* __allocate(size_t size){return (T)malloc(size);}//銷毀內存template <class T>inline void __deallocate(T* buffer){free(buffer);}//構造函數 placement newtemplate <class T1, class T2>inline void __construct(T1* p, const T2& value){new (p) T1(value);}template <class T>inline void __construct(T* ptr){new (ptr) T;}//析構template <class T>inline void __destroy(T* ptr){ptr->~T();}// 模板類:allocator// 模板函數代表數據類型template <class 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 difference_type;private:union _obj {_obj* next;char unuse[1];};static size_t _S_heap_size;_obj* free_list[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };_obj* start, * end;public:static pointer allocate(size_type n){size_type size = UP_ROUND(n);if(size>MAX_BYTES)__allocate((size_type)n);else {_obj** index=free_list + FREE_INDEX(size);_obj* result = *index;if (0 == result) {return refill(size);}*index = result->next;return result;}}static pointer refill(size_type n){int nobj = 20;char* chunk = alloc_chunk(n,nobj);//這里會爆出異常 __THROW_BAD_ALLOCif (1 == nobj)return chunk;/*for (__i = 1; ; __i++) {__current_obj = __next_obj;__next_obj = (_Obj*)((char*)__next_obj + __n);if (__nobjs - 1 == __i) { __current_obj->_M_free_list_link = 0;break;//gnu gcc不喜歡正常循環20次 喜歡直接break出}else {__current_obj->_M_free_list_link = __next_obj;}}*///_obj** index = free_list + FREE_INDEX(size);_obj* result,*current;result = chunk;_obj* pro = (_obj*)((char*)chunk + size);current = pro;//哨兵for (int i = 1; i < nobj; ++i) {pro= (_obj*)((char*)chunk + size);//這里不強制轉換可能跳的數量不對 每次跳sizeof(char) 位才對current->next = pro;current = pro;}current->next = nullptr;return result;}static size_type alloc_chunk(size_type __size, int& __nobjs) {/*四種情況先看看能不能從pool里面割出20個(20是經驗值 就如vector擴容有時是2倍有時是1.5倍)不能看看能不能割出一個一個都不能看看能不能往池子里裝水還是不能就調用一級適配器調用malloc讓操作系統想辦法*/size_type left_bytes = end - start ;//水池剩下的水size_type total_bytes= __size*__nobjs;_obj* result;if (left_bytes >= total_bytes) {result = start;start = start + total_bytes;return result;}else if (left_bytes >= __size) {__nobjs = (int)(left_bytes/__size);total_bytes = __size * __nobjs;result = start;start = start + total_bytes;return result;}else {size_t __bytes_to_get = 2 * total_bytes + UP_ROUND(_S_heap_size >> 4);_obj** __my_free_list;if (left_bytes > 0) {__my_free_list =free_list + FREE_INDEX(left_bytes);((_obj*)start)->next = *__my_free_list;*__my_free_list = (_obj*)start;}start = (char*)__allocate(__bytes_to_get);if (0 == start) {_obj* __p;for (auto __i = __size; __i <= MAX_BYTES;i+=ALIGN ) {__my_free_list = free_list + FREE_INDEX(__i);__p = *__my_free_list;if (0 != __p) {start = __p;end = __p + __i;__p = __p->next;return(alloc_chunk(__size, __nobjs));}}//山窮水盡 因為前面就是malloc的 沒必要再試了 直接報錯__THROW_BAD_ALLOC}}}//static void deallocate(pointer ptr);};} // namespace kstd