手撕源码 alloc

怎么有效的手撕代码呢?
gnu gcc 2.9 的 内存池
在这里插入图片描述

  1. 把代码跑起来
  2. 把代码一个片段拿出来使用
  3. 画出代码运行的流程图
  4. 一行一行的搬运
  5. 在看源码的情况下写出类似的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Algorand的共识协议及其核心的优势

Algorand 设计的初衷 Algorand 想解决的核心问题是&#xff1a;去中心化网络中低延时&#xff08;Latency&#xff09;和高置信度&#xff08;Confidence&#xff09;之间的矛盾。其中&#xff0c;延时指从发起交易到确认交易所需要的时间&#xff1b;置信度指的是发出的交易不…

手撕源码 SQL解析器 sqlparser

怎么有效的手撕代码呢&#xff1f; 源代码&#xff1a;https://github.com/hyrise/sql-parser 把代码跑起来把代码一个片段拿出来使用画出代码运行的流程图一行一行的搬运在看源码的情况下写出类似的demo

针对Algorand所使用的密码相关技术细节进行介绍

关键概念 VRF: 可验证随机函数。简单来说是&#xff1a;vrf,Proof VRF(sk,seed)&#xff0c;sk为私钥&#xff0c;seed为随机种子&#xff1b;通过Verify(proof,pk,seed)验证vrf的合法性。cryptographic sorition: 根据用户本轮的VRF值&#xff0c;自身的权重以及公开的区块链…

内存池的实现1 :重载

#ifndef KSTD_ALLOCATOR_H_ #define KSTD_ALLOCATOR_H_// 这个头文件包含一个模板类 allocator&#xff0c;用于管理内存的分配、释放&#xff0c;对象的构造、析构 // 暂不支持标准库容器 todo::支持萃取#include <new> // placement new #include <cstddef>…

对于Algorand的介绍

介绍 Algorand具有能耗低、效率高、民主化、分叉概率极低、可拓展性好等优点&#xff0c;旨在解决现有区块链项目存在的“不可能三角”&#xff08;高度可扩展的、安全的、去中心化&#xff09;问题。Algorand由MIT教授、图灵奖得主Silvio Micali发起&#xff0c;拥有MIT区块链…

内存池的实现2 类专用的内存适配器

B类增加了嵌入指针 #include<new> #include<ctime> #include<iostream> #include<cstdio> class A { public:A() {printf("next%p\n", next);};static void* operator new(size_t size);static void operator delete(void* phead);static i…

C++学习 高级编程

C 文件和流 到目前为止&#xff0c;目前使用最为广泛的是 iostream 标准库&#xff0c;它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。以下将介绍从文件读取流和向文件写入流。这就需要用到 C 中另一个标准库 fstream&#xff0c;它定义了三个新的数…

内存池的实现3 固定大小的allocator单线程内存配置器

如果我们想使内存管理器用于其他大小不同的类该怎么办呢&#xff1f;为每一个类重复管理逻辑显然是对开发时间的不必要浪费。如果我们看一下前面内存管理器的实现&#xff0c;就会明显地看出内存管理逻辑实际上独立于特定的类 有关的是对象的大小一这是内存池模板实现的良好候选…

C++中文版本primer 第二章变量和基本类型 学习笔记

2.2变量 2.2.1 变量定义 列表初始化 定义一个名字为units_sold的int变量并初始化为0 int units_sold 0; int units_sold {0}; int units_sold{0}; int units_sold(0); C11 用花括号来初始化变量&#xff0c;上面这个步骤也称之为列表初始化。这种初始化有一个重要的特点&…

内存池中的嵌入式指针

嵌入式指针 可以union改struct 内存分配后 next指针就没用了 直接作为数据空间比较省内存 因为对指针指向的内存存储的时候 编译器是不管你是什么类型的 &#xff0c;这里有道练习题可以对指针的概念稍微理解一下&#xff1a; #include <iostream> using std::cout; us…

C++ 标准程序库std::string 详解

现在一般不再使用传统的char*而选用C标准程序库中的string类&#xff0c;是因为string标准程序和char*比较起来&#xff0c;不必担心内存是否足够、字符串长度等等&#xff0c;而且作为一个类出现&#xff0c;集成的操作函数足以完成大多数情况下(甚至是100%)的需要。比如&…

内存池的实现4 alloc内存池

alloc 内存池 优点: &#xff1a;本质是定长内存池的改进&#xff0c;分配和释放的效率高。可以解决一定长度内存分配的问题。 缺点 &#xff1a;存在内碎片的问题&#xff0c;且将一块大内存切小以后&#xff0c;申请大内存无法使用&#xff0c;别的FreeList挂了很多空闲的内存…

C++primer第15章节详解面向对象程序设计

前言 面向程序设计基于三个基本概念&#xff1a;数据抽象、继承和动态绑定。继承和动态绑定可以使得程序定义与其他类相似但是不完全相同的类&#xff1b;使用彼此相似的类编写程序时候&#xff0c;可以在一定程度上忽略掉他们的区别。 OOP概述 oop&#xff08;面向程序的设…

内存池的线程安全问题

malloc/free 据说老版本libc 有俩个版本&#xff0c;当你连接 pthread库的时候它就链接的是线程安全版&#xff0c;否则不是。在glic 2.2 以上无论怎么都是线程安全的。 new/delete new/delete 封装的 malloc/free , 如果malloc/free 是它们就是线程安全的。

C++11命名空间的using说明

std::cin 表示从标准输入读取内容&#xff0c;此处的作用域操作符::是指编译器应该从左侧名字所示的作用域中寻找右侧那个名字。因此std::sin表示使用命名空间std中的cin。 每个名字都需要有独立的using的声明 每一个using声明引入命名空间中的一个成员&#xff0c;比如可以将…

c语音的一些特殊关键字

PRETTY_FUNCTION C语言中获取函数名 C语言中的__LINE__用以指示本行语句在源文件中的位置信息

C++ primer三章二节标准库类型string

标准库类型string 标准库类型string表示可变长的字符序列&#xff0c;使用#include<string>引入头文件&#xff0c;string定义在命名空间std中。 定义和初始化string对象 如何初始化类的对象是由类的本身决定的&#xff0c;类可以定义很多初始化对象的方式&#xff0c;…

vim 不常见但好用的命令

● 跳跃 ○ 向前跳跃是 f ○ 向后跳跃是 F ● 继续 ○ 保持方向是 ; ○ 改变方向是 , ● 可以加上 [count] 来加速 ● ^ 是到本行第一个非空字符 ● 0 是到本行第一个字符&#xff0c;不管是不是空格 ● g_ 是到本行最后一个非空字符 ● 两个按键要依次按下 ● $ 跳到本行最后…

加密机组会 会议纪要

2020年9月28日 1&#xff0c;使用基类继承的机制&#xff0c;调用写好的函数接口 1&#xff0c;不要 使用Content&#xff08;封装数据&#xff0c;本质是一个json字符串&#xff09;&#xff0c;1&#xff0c;因为每次使用这个需要对里面的内容进行序列化&#xff0c;转化成…

c++为什么没有垃圾回收

垃圾回收 内存清理的另一个方面是垃圾回收。在支持垃圾回收的环境中&#xff0c;程序员几乎不必显式地释放与对象关联的 内存。运行时库会在某时刻自动清理没有任何引用的对象。 与C#和Java不一样&#xff0c;在C语言中没有内建垃圾回收。在现代C中&#xff0c;使用智能指针管理…