手撕源碼 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.pswp.cn/news/447085.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447085.shtml
英文地址,請注明出處:http://en.pswp.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;使用智能指針管理…