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. c++病毒函数

    FreeConsole(); 屏蔽输出. BlockInput(); 阻止键盘和鼠标的工作. 所需头文件: #include <windows.h> #include <Winabl ...

  2. FTP文件服务器

    import java.io.InputStream; import java.io.Serializable; import lombok.Data; @Data public class FtpB ...

  3. JS 实现PDF文件打印

    function PdfPrint() {        bdhtml = window.document.body.innerHTML;        sprnstr = "<!-- ...

  4. 01背包(类) UVA 10564 Paths through the Hourglass

    题目传送门 /* 01背包(类):dp[i][j][k] 表示从(i, j)出发的和为k的方案数,那么cnt = sum (dp[1][i][s]) 状态转移方程:dp[i][j][k] = dp[i ...

  5. 线段树+树状数组+贪心 HDOJ 5338 ZZX and Permutations

    题目传送门 /* 题意:不懂... 线段树+树状数组+贪心:贪心从第一位开始枚举,一个数可以是循环节的末尾或者在循环节中,循环节(循环节内部是后面的换到前面,最前面的换到最后面).线段树维护最大值,树 ...

  6. Deepfakes教程及各个换脸软件下载

    源:https://blog.csdn.net/koest/article/details/80720078 Deepfakes目前用于深度换脸的程序基本都是用python编程语言基于tensorfl ...

  7. Git管理多个远程分支

    在此目录下使用GIT要注意一下几点: 因为这个目录是管理远程多个不同的分支的项目,所以使用GIT之前确认一下几点: 打开git bash,使用命令:git config –list查看目前本地的目录文 ...

  8. 全志A33平台编译linux(分色排版)sina33

    全志A33平台编译linux 大文实验室/大文哥 壹捌陆捌零陆捌捌陆捌贰 21504965 AT qq.com 完成时间:2017/12/12 17:36 版本:V1.0 Xshell 5 (Buil ...

  9. esp8266 SOC方案经过半年沉淀之后再度重启

    我发誓这是最后一次玩esp8266,该脱坑了...... 以前看不懂的教程 http://club.gizwits.com/thread-6447-1-1.html 2018教程 http://clu ...

  10. git上手简洁手册

    下载安装git 创建文件夹:learngit 用Git CMD进入文件夹: cd learngit 用Git CMD初始化git: git init 创建文件:新建一个文件在learngit文件夹下, ...