https://github.com/joeyleeeeeee97

目录:

  第二章  空间适配器

  第三章  迭代器

  第四章  序列式容器(vector,list,deque,stack,heap,priority_queue,slist)

  第五章  关联式容器(树的算法 + RB_tree ,set,map,hashtable)

  第六章  算法

  第七章  仿函数

  第八章  适配器(adapet)

第二章  空间适配器

  具有次配置力的SGI空间适配器,STL allocator将对象的内存分配和初始化分离开,内存配置由alloc:allocate 负责,内存释放由deallocate 负责,对象构造操作 由 construct() 负责,对象析构操作由destroy() 负责。

  构造和析构的基本工具:construct 和destory

trivial constructor :: 

In simple words a "trivial" special member function literally means a member function that does its job in a very straightforward manner. The "straightforward manner" means different thing for different kinds of special member functions.

For a default constructor and destructor being "trivial" means literally "do nothing at all". For copy-constructor and copy-assignment operator, being "trivial" means literally "be equivalent to simple raw memory copying" (like copy with memcpy).

If you define a constructor yourself, it is considered non-trivial, even if it doesn't do anything, so a trivial constructor must be implicitly defined by the compiler.

In order for a special member function to satisfy the above requirements, the class must have a very simplistic structure, it must not require any hidden initializations when an object is being created or destroyed, or any hidden additional internal manipulations when it is being copied.

For example, if class has virtual functions, it will require some extra hidden initializations when objects of this class are being created (initialize virtual method table and such), so the constructor for this class will not qualify as trivial.

For another example, if a class has virtual base classes, then each object of this class might contain hidden pointers that point to other parts of the very same object. Such a self-referential object cannot be copied by a simple raw memory copy routine (like memcpy). Extra manipulations will be necessary to properly re-initialize the hidden pointers in the copy. For this reason the copy constructor and copy-assignment operator for this class will not qualify as trivial.

For obvious reasons, this requirement is recursive: all subobjects of the class (bases and non-static members) must also have trivial constructors.

    通过type_traits 判断是不是POD类型然后使用相应的destroy

  

#pragma once
#ifndef _CONSTRUCT_H
#define _CONSTRUCT_H #include<new.h> template<class T1, class T2>
inline void construct(T1* p, const T2& value)
{
new(p) T1(value);
} template<class T>
inline void destroy(T* ptr)
{
ptr->~T();
} //以下是destroy()第二版本 接受两个迭代器此函数设法找出元素的数值型别
//进而利用__type_traits<>求取最适当的措施
template<class FowardIterator>
inline void __destroy(ForwardIterator first, ForwardIterator last, __true_type)
{ } template<class FowardIteraot>
inline void __destroy(ForwardIterator first, ForwardIterator last, __false_type)
{
for (;; first < last; first++)
destroy(&*first);
} template<class FowardIterator,class T>
inline void destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy(first, last, trivial_destructor());
}
#endif

  空间的配置和释放 std::alloc

  SGI对此的设计哲学如下: 向system heap 要求空间;考虑多线程状态;考虑内存不足时候的应变措施;考虑过多“小型区块”可能造成的碎片问题

  双层配置器:第一层直接使用malloc 和free 第二级配置器在大于128bytes的请求下 转为一级配置器分配内存,在小于128bytes的内存请求下,内存池分配。

  

#ifndef _ALLOCATOR_H
#define _ALLOCATOR_H #include<new>
#include<cstddef>
#include<climits>
#include<iostream>
#include<cstdlib>
#include"construct.h"
namespace ministl
{
template<class T>
inline T* _allocate(size_t n, T*)
{
return static_cast<T*>(alloc::allocate(n));
} template<class T>
inline void _deallocate(T* buffer)
{
alloc::deallocate(static_cast<T*>(buffer), sizeof(T));
} 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; template<class U>
struct rebind
{
typedef allocator<U> other;
}; pointer allocate(size_type n,const void* hint = )
{
return _allocate((difference_type)n, pointer());
} void deallocate(pointer p, size_type n)
{
_deallocate(p);
} pointer address(reference x)
{
return (pointer)&x;
} const_pointer const_address(const reference x)
{
return (const_pointer)&x;
} size_type max_size()const
{
return size_type(UINT_MAX / sizeof(T));
}
};
}
#endif
#pragma once
#ifndef _ALLOC_H__
#define _ALLOC_H__
#include <cstdlib>
/*
第二级适配器,当区块小于128bytes时,以内存池管理
*/
namespace ministl
{
class alloc
{
private:
enum {_ALIGN = };//小型区块
enum {_MAXBYTES = };
enum {_NFREELISTS = _MAXBYTES/_ALIGN};
enum { _NOBJS = };
private:
//可以看作确定地址也可以看作指向下一节点
union obj
{
union obj *next;
char client[];
}; static obj* freelist[_NFREELISTS]; private:
static char *start, *end;
static size_t heap_size; private:
static size_t ROUND_UP(size_t bytes)
{
return ((bytes + _ALIGN - )&~(_ALIGN - ));
}
static size_t FREELIST_INDEX(size_t bytes)
{
return (((bytes)+_ALIGN - ) / _ALIGN - );
}
static void* refill(size_t n);
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_size, size_t new_size);
}; char *alloc::start = ;
char *alloc::end = ;
size_t alloc::heap_size = ;
alloc::obj *alloc::freelist[_NFREELISTS] = { ,,,,,,,,,,,,,,, }; void *alloc::allocate(size_t bytes)
{
if (bytes > _MAXBYTES)
{
return malloc(bytes);
}
obj *pos = freelist[FREELIST_INDEX(bytes)];
if (pos)
{
freelist[FREELIST_INDEX(bytes)] = pos->next;
return pos;
}
else
{
return refill(ROUND_UP(bytes));
}
} void alloc::deallocate(void* ptr, size_t bytes)
{
if (bytes > _MAXBYTES)
{
free(ptr);
}
else
{
obj *tmp = (obj *)ptr;
tmp->next = freelist[FREELIST_INDEX(bytes)];
freelist[FREELIST_INDEX(bytes)] = tmp;
}
} void *alloc::reallocate(void *ptr, size_t old_size, size_t new_size)
{
alloc::deallocate(ptr, old_size);
ptr = allocate(new_size);
return ptr;
}
//返回一个大小为n的对象,并且有时候会为适当的freelist增加节点
//假设n已经上调到8的倍数
void *alloc::refill(size_t bytes)
{
size_t nobjs = _NOBJS;
obj **myfreelist = NULL;
obj *result = NULL;
obj *current_obj = , *next_obj = ;
char *chunk = chunk_alloc(bytes, nobjs);
if (nobjs == )
{
return chunk;
}
else
{
myfreelist = freelist+ FREELIST_INDEX(bytes);
//这一块返回给客户端
result = (obj*)chunk;
//下面导引freelist指向新配置的空间(内存池)
*myfreelist = next_obj = (obj*)(chunk + bytes); for (int i = ;; i++)
{
current_obj = next_obj;
next_obj = (obj*)((char*)next_obj + bytes); if (nobjs - == i)
{
current_obj->next = ;
break;
}
else
{
current_obj->next = next_obj;
}
}
return result;
}
}
/*
从链表中分配nobjs个空间,每一块的大小为bytes.如果链表中至少有一个满足要求,那么分配尽可能多的块并且修改nobjs的值,如果数量不足就从内存中分配两倍的空间
*/
char *alloc::chunk_alloc(size_t bytes, size_t &nobjs)
{
char *result = ;
size_t total_bytes = bytes*nobjs;
size_t bytes_left = end - start;
if (bytes_left >= total_bytes)
{
result = start;
start = start + total_bytes;
return result;
}
else if(bytes_left >= bytes)
{
nobjs = bytes_left / bytes;
total_bytes = nobjs*bytes;
result = start;
start = start + total_bytes;
return result;
}
else
{
size_t bytes_to_get = * total_bytes + ROUND_UP(heap_size >> );
if (bytes_left > )
{
obj* volatile *myfreelist = freelist + FREELIST_INDEX(bytes_left);
((obj*)start)->next = *myfreelist;
*myfreelist = (obj*)start;
}
start = (char*)malloc(bytes_to_get);
if (!start)
{
obj **myfreelist = , *p = ;
for (int i = ; i < _MAXBYTES; i += _ALIGN)
{
myfreelist = freelist + FREELIST_INDEX(i);
p = *myfreelist;
if (!p)
{
*myfreelist = p->next;
start = (char*)p;
end = start + i;
return chunk_alloc(bytes, nobjs);
}
}
end = ;
}
heap_size += bytes_to_get;
end = start + bytes_to_get;
return chunk_alloc(bytes, nobjs);
}
} }
#endif

4.3 list

相比較vector的連續空間,list的好處在於每次插入或者刪除一個元素就配置或者釋放一個元素的空間,因此List對於空間的運用绝对的精准,list本身和list的结点是不同的结构需要分开设计。list不能用普通指针作为迭代器因为它的结点不能抱枕在存储空间中连续存在,list迭代器必须有能力指向List的节点并且正确的进行递增递减操作,list是一个双向迭代器。list有一个重要性质,插入和接和操作不会导致原有的迭代器失效。

STL源码剖析 学习笔记 MiniSTL的更多相关文章

  1. c++ stl源码剖析学习笔记(一)uninitialized_copy()函数

    template <class InputIterator, class ForwardIterator>inline ForwardIterator uninitialized_copy ...

  2. c++ stl源码剖析学习笔记(二)iterator

    ITERATOR 迭代器 template<class InputIterator,class T> InputIterator find(InputIterator first,Inpu ...

  3. c++ stl源码剖析学习笔记(三)容器 vector

    stl中容器有很多种 最简单的应该算是vector 一个空间连续的数组 他的构造函数有多个 以其中 template<typename T> vector(size_type n,cons ...

  4. STL源码剖析-学习笔记

    1.模板是一个公式或是蓝图,本身不是类或是函数,需进行实例化的过程.这个过程是在编译期完成的,编译器根据传递的实参,推断出形参的类型,从而实例化相应的函数 2. 后续补充-.

  5. STL源码剖析读书笔记之vector

    STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...

  6. 重温《STL源码剖析》笔记 第三章

    源码之前,了无秘密. --侯杰 第三章:迭代器概念与traits编程技法 迭代器是一种smart pointer auto_Ptr 是一个用来包装原生指针(native pointer)的对象,声明狼 ...

  7. STL源码剖析读书笔记--第四章--序列式容器

    1.什么是序列式容器?什么是关联式容器? 书上给出的解释是,序列式容器中的元素是可序的(可理解为可以按序索引,不管这个索引是像数组一样的随机索引,还是像链表一样的顺序索引),但是元素值在索引顺序的方向 ...

  8. 重温《STL源码剖析》笔记 第六、七、八章 next_permutation (字典序)

    源码之前,了无秘密  ——侯杰 第六章算法 next_permutation 比如:01342 -> 01423 -> 01432 方法:从尾端开始往前寻找两个相邻的元素,令第一个元素为* ...

  9. 重温《STL源码剖析》笔记 第五章

    源码之前,了无秘密  ——侯杰 序列式容器 关联式容器 array(build in) RB-tree vector set heap   map priority-queue multiset li ...

随机推荐

  1. WEB前端学习

    第一日:软件的安装和下载 1.百度搜索推荐使用webStorm前端神器进行开发,傻瓜式安装不必多说! 激活 前提:修改本地的hosts配置文件(/etc/hosts) 最后一行新增这句话:0.0.0. ...

  2. SQL在一张表中根据父ID获取所有的子ID

    with a as ( select id,name,parentid from categories where id=53 union all select x.id,x.name,x.paren ...

  3. 构建一个.net的干货类库,以便于快速的开发 - 工具类

    相信每一个开发的框架都会有一个工具类,工具类的作用有很多,通常我会将最常用的方法放在工具类里 取得用户IP 取得网站根目录的物理路径 枚举相关 非法关键字检查 绝对路径改为相对路径 获取小数位(四舍五 ...

  4. 联想 K5 Pro(L38041)免解锁BL 免rec 保留数据 ROOT Magisk Xposed 救砖 ZUI 5.0.188

    >>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...

  5. grunt 全局使用

    grunt 不同地方使用时需要将插件下载的当前文件夹,这是因为查找模块时是当前路径,这会造成多个工程使用时会需要下载多次,而这些东西又不应该存在于工程之中,所以应该将所有模块全局安装,然后在工程下面只 ...

  6. Knockout 实例

    定义见:http://baike.baidu.com/item/Knockout/18611883#viewPageContent 此处仅列举一个小例子 <p> <select da ...

  7. nginx--提供一键安装脚本

    nginx特点 基于进程池实现的fastcgi 单一进程即可实现处理上千的连接 易于扩展的插件系统 安装篇 *下载源码 curl -O http://nginx.org/download/nginx- ...

  8. vue组件---动态组件&异步组件

    (1)在动态组件上使用keep-alive 之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件.接下来简单回顾下 <component>元素是vue 里面的一个内置组件.在里面使 ...

  9. ThinkPHP---TP功能类之验证码

    [一]验证码 验证码全称:captcha(全自动识别机器与人类的图灵测试),简单理解就是区分当前操作是人执行的还是机器执行的 常见验证码分3种:页面上图片形式.短信验证码(邮箱验证可以归类到短信验证码 ...

  10. 【转载】原 IntelliJ IDEA (idea)引入eclipse web项目

    原文地址:http://my.oschina.net/u/1170781/blog/192731 摘要 概述IntelliJ IDEA,以后都简称为idea,鼓捣了很久,看了很多例子才搞出来,希望对其 ...