自己动手实现简易STL

  • STL六个组件
    • 迭代器 & 算法
    • 容器,迭代器部分
    • 适配器
    • 仿函数
  • 额外的工作
  • 小结

之前学习C++看侯老师的书的时候实现了一下STL的基本组件,包括了6个组件,allocator, iterator, container, trait, functor, algorithm的组件,也是终于搞清楚了6个组件之间的相互关联.分享给大家。

STL六个组件

比较难理解的就是萃取器和迭代器还有算法之间的交互。其实就是一个算法库根据你迭代器属于不同类型进行的一个选择,选择相对最优的方法。下面展示一下核心部分。对应于STL的容器,分别是单向,双向,随机访问迭代器。

class input_iterator {};
class forward_iterator :public input_iterator {};
class bidirectional_iterator :public forward_iterator {};
class random_acess_iterator final: public bidirectional_iterator {};

用继承关系来表达这样一个迭代器的从属关系的原因是由于C++的一个机制,是利用重载的机制。我们首先考虑public继承关系是一个 is a 的关系,那么再这个层次的继承关系中,random_acess_iterator 是最为特殊的一个。
所以从特殊性的角度来考虑 (从特殊性来比较): random_acess_iterator > bidirectional_iterator > forward_iterator ,他们都是input_iterator。
C++的重载是有一个机制,如果有多个同时可以匹配的选择最特殊的那个,这个机制仔细想想也OK,既然我可以匹配更特殊的,何必匹配更加泛化的呢。
下面举一个最简单的算法例子就懂了。
计算两个迭代器之间的距离。

迭代器 & 算法

下面这个是调用函数,可以看到他还调用了一个_distance函数来作为辅助函数。

template<class InputIterator>
unsigned int distance(InputIterator first, InputIterator last)
{return _distance(first, last, Traits<InputIterator>::iterator_type());
}

辅助函数一:

template<class InputIterator>
unsigned int _distance(InputIterator first, InputIterator last, random_acess_iterator iter){return abs::abs(last - first);
}

第一行是为了debug的,后面一行可以看到只需要做一个减法就可以计算first到last的长度了。也就是O(1)的时间。为什么可以用减号,因为所有的随机访问迭代器都重载了 operator -
可以看到第三个参数就是做了这样一个选择。

辅助函数二:

template<class InputIterator>
unsigned int _distance(InputIterator first, InputIterator last, forward_iterator iter){unsigned int dis = 0;for (; first != last; ++first)++dis;return dis;
}

对于其他类型来说,我不能和随机访问迭代器一样,因此只能一个一个地加了,所以是O(last - first)的时间复杂度。

这里就体现了为什么需要迭代器,就是为了性能!

Q:为什么我不直接用这种重载的方式,非要加一个间接的调用层啊。
A: 因为容器有很多种,每个容器对应的迭代器实际是对应容器的特化的迭代器。但是这种重载机制需要迭代器的类型。而这个需要的类型是特化的那几种迭代器。
举个例子就是 deque和vector 都是random_acess_iterator.但是相应的算法具体是针对某个iterator。所以加入直接使用而不加这个distance的间接,是没有办法找到。或者你需要向里面一样复杂的写法,而又希望接口简单,隐藏细节,因此采用这种写法。

容器,迭代器部分

对于每个可以整迭代器的容器,都会有一个与之相当于的迭代器的,并且他们的关系是耦合的,也就是你实现一个容器,需要实现一个对应的迭代器才能加入STL的大家庭。当然也不是必须这么做,因为有的数据结构没法设计迭代器。能这么设计的好处就是你可以用标准库的算法。
下面简单列一下大概的结构。

template<class T>
class iterator{//用同意的来表示其数据或者容器的特性。using iterator_type = ...;...// 需要的重载,不多不少operator ++(){}operator ++(int){}operator != (const iterator&) {}...
};template<class T, class Alloc = alloc>
class container{public:// 表示其类型,方便萃取器trait来萃取类型。using value_type = T;using iterator = ...;...//函数实现 字段等等container();...
};

这样一说,就只有allocator没有说了,这里推荐看侯捷老师的内存管理,里面讲到了这种简单的实现,以及SGI的二层分配,也讲了一个loki的能够消除内部碎片的分配器。
这里为了简化,只是用了简单的new delete。
注意这里是不能使用 malloc 或者free的 除非你显示地调用对象析构函数。

class easy_allocator{public:template<class T>static T* alloc(){return new T();}template<class T>static void dealloc(T* p){assert(p != nullptr);delete p;}
};

适配器

这个没有太多可以说的,你可以认为就是接口之间的转换。比如queue stack。举个例子就是queue 我需要先进先出 也就是push_back() & pop_front()两种操作, 因此我可以选择list deque。
那么对于stack来说 我需要push_back() & pop_back() 那么vector list deque都可以作为我的底层实现。你在使用标准库的时候也会看到你可以再模板自己定义一个类型。

stack<int, vector<int>> st;
queue<int, deque<int>> que;

仿函数

functor 就是为了让标准库的容器, 算法使用更加灵活。C++11之后很多接口可以直接用lambda 非常好用。

额外的工作

当时觉得这么写代码(CTRL + C + V)有点没有意思,于是当时想能不能稍微扩充个整个小玩具。于是封装win平台的窗口作为一个类, 实现了一个相当于一个 容器的 一个可视化。(并没有很好的完善,后面完善一下 贴出源代码。) 封装window窗口创建作为一个类 网络上可以查一下,有点点技巧。
使用方式类似与迭代器,因为是直接和容器相关的。类似于这样是直接耦合再一起

using window = window_vector<T>;

能够简单的可视化一些数据结构,也还是稍微有点意思吧。。。还增加的个按钮 可以看到你最近的操作是怎么变化的。


这个就是一个二叉树的啦。可以看到插入一个元素对他带来的变化。
红黑树 具体的变化:
红黑树就是不像AVL树对于高度那样严格,通过红黑节点的定义(有证明说明红黑树是和2-3-4树本质是一样的)
并且红黑树旋转的一个很重要性质就是: O(1)的旋转进行插入或者删除,对比AVL树是O(lgn)的旋转数。



这个是list的window…


而且用这个窗口可以很好的debug,比如树可以直观的看里面的东西对不对,print出来不太直观。
这些实现要注意窗口resize的消息,需要重新绘制一下。没有加入滚动条的功能,有时间再加。

小结

非常推荐去实现一个vector 包括所有的组件,其实也不是那么简单。不需要实现那么多算法 容器等,知道6个组件具体是怎么工作的就够了。
这里简洁一下6个组件如何交互,下篇文章会用最简单的vector举例子 示范一个具体的实现。

了解标准库,可以更好地扩展他。比如怎么使用它底层的分配器,容器等等。根据自己的需求进行选择,甚至可以做必要的扩充。

初学者,欢迎各位指出问题。

自己动手实现简易STL相关推荐

  1. 自己动手实现简易代码生成器、采用文本模板文件生成服务层、服务层接口代码的做法参考...

    为什么80%的码农都做不了架构师?>>>    最近受到 单程列车 http://www.cnblogs.com/zhaojingjing/  的启发,让我做一个模板文件来生成代码, ...

  2. 动手实现简易端口扫描器——PortScanner

    文章目录 效果展示 前言 系列介绍 举例子&打比方 何为端口 物理端口 虚拟端口 TCP&UDP 文章介绍 设计分析 设计实现 关于GIL 效果展示 本地服务器状态图: 前言 系列介绍 ...

  3. 动手实现简易PHP一句话连接工具——FruitKnife

    文章目录 效果展示 连接一句话 浏览服务器目录 打开文件 跳转目录 上传文件 前言 设计思路与需求分析 功能实现 连接一句话 浏览目录 打开文件 跳转路径 上传文件 节目清单 不足之处 工具名字的由来 ...

  4. 动手实现简易网站目录扫描器——WebScanner

    效果展示 项目目录: 引言 不知是否有小伙伴在学习Web安全相关的知识,如果有的话,那应该对XSS,SQL注入,文件上传,一句话脚本等等基本功应该是再熟悉不过了.最初学习的时候是它,实战最先测试的也是 ...

  5. 动手实现简易网站目录扫描器(桌面窗口版)——WebScannerTkl

    效果展示 项目目录,与命令行版扫描器同: 前言 这篇文章与前一篇原理相同,都是对生成的可能链接进行试错验证,所以我们不再讨论原理部分,主要内容放在语言的继承和窗口的可视化上. 图形化界面我采用了tki ...

  6. 【并发编程】Future模式及JDK中的实现

    本文讲解Java中Future模式的使用,文章也发布在了公号(点击查看),欢迎交流. 1.1.Future模式是什么 先简单举个例子介绍,当我们平时写一个函数,函数里的语句一行行同步执行,如果某一行执 ...

  7. 如何通过自学找到一份开发的工作?

    01 学习过程 比较仔细的学习了<c++primer>,并对每个习题都自己写代码实现了一遍,包括稍微复杂一点的例子. 认真读完了<effective c++>,<effe ...

  8. 人工智能之自动驾驶系列(一):概要

    人工智能之自动驾驶系列(一):概要 蓬生麻中 http://blog.csdn.net/wangdaiyin/article/details/77403592 版权声明:本文系个人经多处资料学习.吸收 ...

  9. 肺活量测试软件原理,测测你的肺活量 肺活量测试装置小发明小实验

    大家都知道每个人都有一个呼吸器官--肺,肺的功能是吸进新鲜空气,给人体供给氧气,呼出废气--二氧化碳.每个人的肺活量都不一样,有的人肺活量挺大,潜水.跑步都很厉害.早在三年级的<科学>课上 ...

  10. 不需要网络的调频收音机_五六十年代不需要电的收音机

    说起矿石收音机,老一辈的无线电爱好者可以说人人都是从这里起步的,而年青的电子爱好者却不见得知道它究竟是何方神圣. 上世纪五六十年代,物质极端贫乏,如果谁家有一台电子管收音机,那不亚于现在拥有一辆奔驰宝 ...

最新文章

  1. Error in do_one(nmeth) : NA/NaN/Inf in foreign function call (arg 1)
  2. APUE(第七章)进程环境
  3. 黑帽SEO:Google为什么会屏蔽你的网站
  4. python之模块csv之CSV文件一次写入多行
  5. LOJ #2734 Luogu P3615 [JOI2016春季合宿]Toilets (结论、贪心)
  6. 【Notes8】Linux开发环境,Linux命令,vi命令,/正则,Hash,iNode,文件查找与读取,Linux开机自启动
  7. 教你如何定位及优化SQL语句的性能问题
  8. python io操作有什么_Python文件IO操作
  9. css3毛玻璃效果白边问题
  10. centos usb转网口_centOS安装与配置minicom(串口转USB)
  11. redis java 发布订阅_Redis之发布订阅(Java)
  12. Linux 的 复制命令 【 cp 】 (copy)及其 (常用参数 -fp)
  13. C语言实现呼吸灯(HAL库)
  14. Docker 从入门到实战视频教程(15 个视频)
  15. 如何生成一个APP_ID
  16. 张小龙4个小时演讲全文:每天有1亿人教我做产品(下)
  17. python斜杠用法_Python中正反斜杠(‘/’和‘\’)的意义与用法
  18. php抖音小程序登录后端代码
  19. 【优雅的避坑】不安全!别再共享SimpleDateFormat变量了
  20. VB中实现IObjectSafety接口以声明控件安全的方法

热门文章

  1. Unity3D AssetBundle打包与加载
  2. Revit模型轻量化方法
  3. 软件系统开发步骤包括哪些过程?
  4. 机器人工作空间解析分析
  5. BERT 中wordPiece的原理
  6. 各利不同网站的盈利模式
  7. 读周志华《机器学习》第一章有感(白话总结)
  8. vscode好用插件——磨刀不误砍柴工!
  9. Lua游戏客户端框架通用功能模块
  10. python删除csv某一行_python删除csv行