设计一个小型的内存池以及链表

上一节撸到万事俱备只欠真正的lex, 但是lex的作用是将源代码转化为Token流, 用什么保存Token? 这就涉及到我们要接触的第一个数据结构—链表, 虽然标准库中很多容器都可以承担链表的任务, 但是我说过出于锻炼原因, 我会尽量不使用stl中的容器, 所以我决定自己撸一个链表出来, 既然之后大多数的容器都要自己撸, 干脆连内存池也一并撸一个出来, 所以这一节的两个目的就是 : 内存池以及基于这个内存池的链表.

我个人接触内存池的时间不长, 准确的说我目前脑袋里面只有两中内存池的思路, 一种是sgi stl内存池,我之前有一篇文章专门对这种内存池做过讲解, 但是这里我会使用另外一种较为简易的内存池模型, 因为我认为sgi stl准确来说可以支持频繁地不同大小的内存分配, 而我这里会使用一种简化的思路, 使之每一个内存池只支持单一大小的内存分配. 这种内存池也是从别人那里学过来的, 简图差不多是这样.

然后源代码差不多是这样...

  1. #ifndef FRED_MEMORYPOOL_H
  2. #define FRED_MEMORYPOOL_H
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <vector>
  6. template <typename T, size_t NumberForOneNode = 32>
  7. class MemoryPool{
  8. private:
  9. struct node{
  10. void* space;
  11. node* next;
  12. };
  13. node *head, *tail;
  14. size_t left;
  15. void* cur;
  16. protected:
  17. MemoryPool():left(NumberForOneNode){
  18. tail = head = new node;
  19. head->next = 0;
  20. cur = head->space = static_cast<T*>(malloc(sizeof(T) * NumberForOneNode));
  21. }
  22. //Big three
  23. MemoryPool(const MemoryPool&) = delete;
  24. MemoryPool& operator=(const MemoryPool& rhs) = delete;
  25. ~MemoryPool();
  26. void* allocate();
  27. };
  28. template <typename T, size_t NumberForOneNode>
  29. MemoryPool<T, NumberForOneNode>::~MemoryPool() {
  30. while(true) {
  31. if (head == tail) {
  32. free(head->space);
  33. delete head;
  34. return;
  35. }
  36. auto temp = head;
  37. head = head->next;
  38. free(temp->space);
  39. delete temp;
  40. }
  41. }
  42. template <typename T, size_t NumberForOneNode>
  43. void* MemoryPool<T, NumberForOneNode>::allocate() {
  44. if(left--){
  45. auto re = cur;
  46. cur = reinterpret_cast<char*>(cur) +sizeof(T);
  47. return re;
  48. }
  49. left = NumberForOneNode;
  50. auto newNode = new node;
  51. newNode->next = 0;
  52. tail = tail->next = newNode;
  53. cur = newNode->space = static_cast<T*>(malloc(sizeof(T) * NumberForOneNode));
  54. allocate();
  55. }
  56. #endif //FRED_MEMORYPOOL_H

图上的变量和代码里面的变量名字都是统一的, 很好理解...

这个内存池的最后一步, 是在这个内存池的基础上, 再套一层封装.

  1. #ifndef FRED_ALLOCATOR_H
  2. #define FRED_ALLOCATOR_H
  3. #include "MemoryPool.h"
  4. template <typename T, size_t NumberForOneNode = 32>
  5. class Allocator : private MemoryPool<T, NumberForOneNode> {
  6. private:
  7. void* buffer[NumberForOneNode];
  8. size_t left;
  9. public:
  10. Allocator():left(0){};
  11. void* allocator(){
  12. if(left){
  13. return buffer[--left];
  14. }
  15. else{
  16. return MemoryPool<T, NumberForOneNode>::allocate();
  17. }
  18. }
  19. void deallocator(T* ptr){
  20. ptr->~T();
  21. if(left == NumberForOneNode){
  22. //full
  23. return;
  24. }
  25. buffer[left++] = ptr;
  26. }
  27. };
  28. #endif //FRED_ALLOCATOR_H

思想其实很简单, 就是如果有空间被送回, 并不直接交还给系统, 而是用这个叫做buffer的数组存着, 如果之后再有需要, 优先从数组中取, 其实这里用vector要比buffer更好, 但是如果想要重利用的空间规模不大的话, buffer也够用, 就算这个buffer也不会内存泄漏, 只是有一些空间被浪费了, 等到维护这个allocator的类卒了, 空间还是要被释放的.

如果想看这个内存池的原版本实现, 可以看这里

原版本实现

有了内存池, 根据我们的需求我们只需要一个链表.

  1. #ifndef FRED_LINKLIST_H
  2. #define FRED_LINKLIST_H
  3. #include "MemoryPool/Allocator.h"
  4. template <typename T>
  5. class LinkList{
  6. private:
  7. struct node{
  8. T item;
  9. struct node* next;
  10. };
  11. Allocator<node> allocator;
  12. node* head;
  13. node* cur;
  14. size_t size;
  15. public:
  16. LinkList():head(0), cur(0), size(0){}
  17. LinkList(const LinkList&) = delete;
  18. LinkList& operator=(const LinkList&) = delete;
  19. ~LinkList(){
  20. for(auto temp = head; temp != cur; temp = temp->next){
  21. allocator.deallocator(temp);
  22. }
  23. allocator.deallocator(cur);
  24. }
  25. void pushBack(const T& item){
  26. if(cur) {
  27. cur = cur->next = reinterpret_cast<node*>(new(allocator.allocator())T(item));
  28. }else {
  29. cur = head = reinterpret_cast<node*>(new(allocator.allocator())T(item));
  30. }
  31. ++size;
  32. cur->next = 0;
  33. }
  34. node* getHead() const {
  35. return head;
  36. }
  37. };
  38. #endif //FRED_LINKLIST_H

对于这个链表功能和实现都很简单, 这里唯一要说可能有些人不知道new可以指定空间进行初始化, 不知道的可以去网上看一下, 这是placement new而我们一般使用的带有内存分配的叫做plain new...

大概就是这么多, 这个礼拜在成都玩, 可能更新地比较慢...

Lexer的设计--中(4)的更多相关文章

  1. 数据库设计中的Soft Delete模式

    最近几天有点忙,所以我们今天来一篇短的,简单地介绍一下数据库设计中的一种模式——Soft Delete. 可以说,该模式毁誉参半,甚至有非常多的人认为该模式是一个Anti-Pattern.因此在本篇文 ...

  2. UI设计中的48dp定律【转】

    有朋友建议我偶尔写写技术类的文章,所以我打算开始穿插性的写一些偏技术方面的科普文章,尽量往小白能看懂的方向写,今天我来讲讲UI设计中的48dp定律. 那么先说说什么是dp ?其实对于一个非技术人员要把 ...

  3. 浅谈UI设计中妙用无穷的深色系背景

    英文:medium 译者:优设网 - 陈子木 链接:http://www.uisdc.com/ui-benefits-of-dark-background# --------------------- ...

  4. web设计中那些因素可能影响网站后期优化

    web设计中那些因素可能影响网站后期优化. 1.网站代码的简洁实用性.网站源文件html代码.js代码.css代码等应尽可能的压缩处理.能用jquery-min.js的最好不要用jquery.js:c ...

  5. UI设计中px、pt、ppi、dpi、dp、sp之间的关系

    UI设计中px.pt.ppi.dpi.dp.sp之间的关系 武汉AAA数字艺术教育 2015-07-24 14:19:50 职业教育 pi px 阅读(3398) 评论(0) 声明:本文由入驻搜狐公众 ...

  6. 在你设计中可能用到的20个杂志 PSD 原型

    你是否正在为您的印刷产品找一些现成的原型素材?在这里,我们收集了一组免费的杂志 PSD 素材,必将派上用场.这些原型将给你和你的客户一个先睹为快的产品,在现实生活中看起来如何.所有这些原型提供了可以免 ...

  7. iOS设计中的“代理”

    “代理”--在iOS的开发设计中是一个非常重要的概念,同时又是十分基础的知识.所以,掌握“代理”势在必行! 以下,结合一个具体的例子,详细认识“代理”: 1, 图例解释: ①:定义两个文本输入框UIT ...

  8. AXURE在原型设计中的应用

    转: http://uedc.163.com/2248.html 前言 什么是原型呢? 产品原型简单的说就是产品设计成形之前的一个简单框架,对网站来讲,就是将页面模块.元素进行粗放式的排版和布局,深入 ...

  9. 网页设计中常用的19个Web安全字体

    来自http://www.jb51.net 在Web编码中,CSS默认应用的Web字体是有限的,虽然在新版本的CSS3,我们可以通过新增的@font-face属性来引入特殊的浏览器加载字体.但多数情况 ...

随机推荐

  1. xv6进程切换-swtch函数

    https://blog.csdn.net/Swartz2015/article/details/61615603 xv6进程切换-swtch函数 进程切换中由于需要保存当前进程的寄存器状态信息,又要 ...

  2. 数据库筛选用户,然后去掉一部分(列表求差),再随机返回一个用户。sqlalchemy + python集合(set) + random

    sqlalchemy和flask-sqlalchemy之间的东西不是太清晰. sqlalchemy文档太他妈多了.日. 今天遇到的实例. 用户进行随机匹配,系统随机返回一个一定筛选条件下的用户.为了用 ...

  3. Xcode6 模拟器路径

    Xcode6公布后,出现了非常多的变动,功能性的变动,在这里不进行过多的赘述,在WWDC上苹果已经进行了讲述,网上也有非常多文章,这里要介绍的是一些不太easy发现的,但非常重要的小地方.      ...

  4. css3-5 css3鼠标、列表和尺寸样式怎么用(文字有关的样式会被继承)

    css3-5  css3鼠标.列表和尺寸样式怎么用(文字有关的样式会被继承) 一.总结 一句话总结:css标签中文字有关的样式会被继承.由常用样式记起. 1.鼠标常用样式有哪些? cursor:poi ...

  5. 百度UEditor图片上传、SpringMVC、Freemarker、Tomcat、Nginx、静态资源

    个人官网.公司项目都需要 可视化编辑器,百度UEditor做得很不错,就用的这个.项目后台用到了SpringMVC.Freemarker,开发过程中部署在Jetty,线上部署用Tomcat,最后可能配 ...

  6. NSOperationQueue小结

    将建立的线程增加队列之中.他们都是并发运行的  假设想有一个线程在另外一个线程之后再运行的话 有一个方法能够实现- (void)addDependency:(NSOperation *)op; 这一个 ...

  7. Thread和ThreadPool

    Thread和ThreadPool 说到多线程异步编程,总会说起Thread.ThreadPool.Task.TPL这一系列的技术.总结整理了一版编程示例和实践,分享给大家. 先从Thread和Thr ...

  8. 汉高澳大利亚matrix矩阵计算器

    我在梦中的超级计算机超级计算机锯,使用大量阵列的cpu记忆,完成并行计算.一个手机制造商由于使用普通机械提供的服务,往往造成停机.是铁道部列车网络售票的事实. 无法使用云服务.上万台计算机并行处理,因 ...

  9. Delphi新手跟我学写CALL,附完整原程序

    在开始进入正题前先罗嗦几句: 1.本人也刚学Delphi不久,也刚通过<诛仙>游戏的绝大部分CALL不久.所以在以下所说所列举的例子并不算是名门正中的写法,如有不当,请各位原谅. 2.本人 ...

  10. Quartz 入门详解 专题

    Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that a ...