怎么有效的手撕代码呢?
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