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. loadrunner乱码解决

    对于Virtual User Generator,本机编码方式为GB2312,GBK,GB18030,因此要修改为utf-8 1.录制过程产生的乱码解决方法: 在tool→recording opti ...

  2. O(1)的快速乘

    那么 有位神仙已经说了O(1)的算法(当然不是我) 这是一种骚操作 直接放代码了啊 inline LL mul(LL a,LL b,LL Mod){ LL lf = a * ( b >> ...

  3. 数据结构之顺序队列(C实现)

    一.队列是什么 队列是一种可以实现“先进先出”的存储结构. 队列通常可以分为两种类型: 一.顺序队列,采用顺序存储,当长度确定时使用. 顺序队列又有两种情况: ①使用数组存储队列的称为静态顺序队列. ...

  4. 二分图最大匹配(匈牙利算法) UVA 10080 Gopher II

    题目传送门 /* 匈牙利算法:这题比UVA_670简单,注意是要被吃的鼠的最少个数,套模板 */ #include <cstdio> #include <algorithm> ...

  5. 利用反射给JAVABEAN实例赋值

    为简化和统一,需要给javabean实例统一赋值,实现代码如下(已测试) import java.util.ArrayList; import java.util.Date; import java. ...

  6. javascript 信息的发布与删除

    现在很多类似以微博发布动态的效果,下面为一个用 JavaScript写的小小的类似微博发布信息的案例 <!DOCTYPE html> <html lang="en" ...

  7. python 关于一个懒惰和非懒惰的

    >>> pa = re.compile(r'<.*>') >>> result = pa.findall('<H1>title</H1 ...

  8. 廖雪峰 Git教程学习笔记 原文 http://www.liaoxuefeng.com/

    一 .集中式与分布式        先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推 ...

  9. CentOS7上安装稻壳CMS

    CentOS7上安装稻壳CMS 1, 安装用途 为了给某公司建设一个小型网站,租用了一个阿里云ECS服务器,最基础的硬件配置,因此选择了CentOS7操作系统. 稻壳CMS(docCMS)源于深喉咙C ...

  10. iOS设计模式——Category和 Extension

    什么是Category Category模式用于向已经存在的类添加方法从而达到扩展已有类的目的,在很多情形下Category也是比创建子类更优的选择.新添加的方法同样也会被被扩展的类的所有子类自动继承 ...