STL:Allocate学习笔记

决定还是两个都看,原来那个tinystl只注释,新的手打。
allocate的设计,我只能说,是精妙到姥姥家了,太精妙了!
但是也太难了…………
allocator.h

#ifndef _ALLOCATOR_H_
#define _ALLOCATOR_H_

#include "Alloc.h"
#include "Construct.h"

#include <cassert>
#include <new>

namespace TinySTL{

	/*
	**空间配置器,以变量数目为单位分配
	*/
	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;
	public:
		static T *allocate();//只分配一个T的内存空间
		static T *allocate(size_t n);//分配n个
		static void deallocate(T *ptr);//释放
		static void deallocate(T *ptr, size_t n);
		//给定指针构建对象
		static void construct(T *ptr);
		static void construct(T *ptr, const T& value);
		//析构
		static void destroy(T *ptr);
		static void destroy(T *first, T *last);
	};

	template<class T>
	T *allocator<T>::allocate(){
		return static_cast<T *>(alloc::allocate(sizeof(T)));
	}
	template<class T>
	T *allocator<T>::allocate(size_t n){
		if (n == 0) return 0;
		return static_cast<T *>(alloc::allocate(sizeof(T) * n));
	}
	template<class T>
	void allocator<T>::deallocate(T *ptr){
		alloc::deallocate(static_cast<void *>(ptr), sizeof(T));
	}
	template<class T>
	void allocator<T>::deallocate(T *ptr, size_t n){
		if (n == 0) return;
		alloc::deallocate(static_cast<void *>(ptr), sizeof(T)* n);
	}

	template<class T>
	void allocator<T>::construct(T *ptr){
		new(ptr)T();
	}
	template<class T>
	void allocator<T>::construct(T *ptr, const T& value){
		new(ptr)T(value);
	}
	template<class T>
	void allocator<T>::destroy(T *ptr){
		ptr->~T();
	}
	template<class T>
	void allocator<T>::destroy(T *first, T *last){
		for (; first != last; ++first){
			first->~T();
		}
	}
}

#endif

alloc.h

#ifndef _ALLOC_H_
#define _ALLOC_H_

#include <cstdlib>

namespace TinySTL{

	/*
	**空间配置器,以字节数为单位分配
	**内部使用
	*/
	class alloc{
	private:
		//所谓小型区块链就是说list里面一共有128/8=16个区块,每个区块地址依次加8。
		//也就是每一块的内存大小依次是8,16,24/32……120,128
		enum EAlign{ ALIGN = 8};//小型区块的上调边界
		enum EMaxBytes{ MAXBYTES = 128};//小型区块的上限,超过的区块由malloc分配
		enum ENFreeLists{ NFREELISTS = (EMaxBytes::MAXBYTES / EAlign::ALIGN)};//free-lists的个数
		enum ENObjs{ NOBJS = 20};//每次增加的节点数
	private:
		//free-lists的节点构,使用union构造,节省内存,柔性数组
		union obj{
			union obj *next;//下一个区块的地址
			char client[1];//用char去申请内存
		};

		static obj *free_list[ENFreeLists::NFREELISTS];
	private:
		//静态变量初始化一次
		static char *start_free;//内存池起始位置
		static char *end_free;//内存池结束位置
		static size_t heap_size;//堆区大小
	private:
		//位运算求2^n次方的倍数
		static size_t ROUND_UP(size_t bytes){
			return ((bytes + EAlign::ALIGN - 1) & ~(EAlign::ALIGN - 1));
		}

		//根据区块大小,决定使用第n号free-list,n从0开始计算
		static size_t FREELIST_INDEX(size_t bytes){
			return (((bytes)+EAlign::ALIGN - 1) / EAlign::ALIGN - 1);
		}

		//返回一个大小为n的对象,并可能加入大小为n的其他区块到free-list
		static void *refill(size_t n);
		//配置一大块空间,可容纳nobjs个大小为size的区块
		//如果配置nobjs个区块有所不便,nobjs可能会降低
		static char *chunk_alloc(size_t size, size_t& nobjs);

	public:
		static void *allocate(size_t bytes);
		static void deallocate(void *ptr, size_t bytes);
		static void *reallocate(void *ptr, size_t old_sz, size_t new_sz);
	};
}

#endif

alloc.cpp

#include "../Alloc.h"

namespace TinySTL{
	//对静态变量初始化
	char *alloc::start_free = 0;
	char *alloc::end_free = 0;
	size_t alloc::heap_size = 0;
	//obj *free_list[ENFreeLists::NFREELISTS]每个前面都加了作用域
	alloc::obj *alloc::free_list[alloc::ENFreeLists::NFREELISTS] = {
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	};

	//成员函数
	void *alloc::allocate(size_t bytes){//分配内存
		if (bytes > EMaxBytes::MAXBYTES){//申请内存大于预设定内存
			return malloc(bytes);//调用malloc
		}
		size_t index = FREELIST_INDEX(bytes);//计算索引号
		obj *list = free_list[index];
		if (list){//此list还有空间给我们
			free_list[index] = list->next;//移向下一个内存
			return list;//返回地址
		}
		else{//此list没有足够的空间,需要从内存池里面取空间
			return refill(ROUND_UP(bytes));
		}
	}
	void alloc::deallocate(void *ptr, size_t bytes){
		if (bytes > EMaxBytes::MAXBYTES){
			free(ptr);
		}
		else{
			size_t index = FREELIST_INDEX(bytes);
			obj *node = static_cast<obj *>(ptr);
			node->next = free_list[index];
			free_list[index] = node;
		}
	}
	void *alloc::reallocate(void *ptr, size_t old_sz, size_t new_sz){
		deallocate(ptr, old_sz);
		ptr = allocate(new_sz);

		return ptr;
	}

	//返回一个大小为n的对象,并且有时候会为适当的free list增加节点
	//假设bytes已经上调为8的倍数
	void *alloc::refill(size_t bytes){
		size_t nobjs = ENObjs::NOBJS;//一次取20个
		//从内存池里取
		char *chunk = chunk_alloc(bytes, nobjs);
		obj **my_free_list = 0;
		obj *result = 0;
		obj *current_obj = 0, *next_obj = 0;

		if (nobjs == 1){//取出的空间只够一个对象使用
			return chunk;
		}
		else{
			my_free_list = free_list + FREELIST_INDEX(bytes);
			result = (obj *)(chunk);
			*my_free_list = next_obj = (obj *)(chunk + bytes);
			//将取出的多余的空间加入到相应的free list里面去
			for (int i = 1;; ++i){
				current_obj = next_obj;
				next_obj = (obj *)((char *)next_obj + bytes);
				if (nobjs - 1 == i){
					current_obj->next = 0;
					break;
				}
				else{
					current_obj->next = next_obj;
				}
			}
			return result;
		}
	}
	//假设bytes已经上调为8的倍数
	char *alloc::chunk_alloc(size_t bytes, size_t& nobjs){
		char *result = 0;
		size_t total_bytes = bytes * nobjs;//总字节
		size_t bytes_left = end_free - start_free;//实际字节

		if (bytes_left >= total_bytes){//内存池剩余空间完全满足需要
			result = start_free;
			start_free = start_free + total_bytes;//更新起点
			return result;
		}
		else if (bytes_left >= bytes){//内存池剩余空间不能完全满足需要,但足够供应一个或以上的区块
			nobjs = bytes_left / bytes;
			total_bytes = nobjs * bytes;
			result = start_free;
			start_free += total_bytes;//榨取能提供的
			return result;
		}
		else{//内存池剩余空间连一个区块的大小都无法提供
			size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);//除了两倍多分配一点
			if (bytes_left > 0){//heap_size什么时候用?
				obj **my_free_list = free_list + FREELIST_INDEX(bytes_left);//把剩下的榨取了转移到新内存
				((obj *)start_free)->next = *my_free_list;//start_free被强制转换为obj型,然后把list地址赋值
				*my_free_list = (obj *)start_free;//相当于加了个中间变量
			}
			start_free = (char *)malloc(bytes_to_get);//需要的空间
			if (!start_free){//heap空间不足,补充内存池
				obj **my_free_list = 0, *p = 0;//
				for (int i = 0; i <= EMaxBytes::MAXBYTES; i += EAlign::ALIGN){//
					my_free_list = free_list + FREELIST_INDEX(i);//寻找尚有未用的区块
					p = *my_free_list;
					if (p != 0){
						*my_free_list = p->next;
						start_free = (char *)p;
						end_free = start_free + i;
						return chunk_alloc(bytes, nobjs);//递归调用自己
					}
				}
				end_free = 0;
				//这似乎应该再去调用一次一级适配器
			}
			heap_size += bytes_to_get;
			end_free = start_free + bytes_to_get;
			return chunk_alloc(bytes, nobjs);//递归调用自己,修正数据
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值