C++学习笔记总结练习:STL源码解析

该博客围绕STL源码展开分析。介绍了STL六大组件的功能与运用,包括容器、算法、迭代器等;阐述了SGI特殊的空间配置器std::alloc及内存基本处理工具;讲解了迭代器相应型别和__type_traits;还涉及序列式容器中的vector等内容。

STL源码分析

STL概论与版本简介

1.STL六大组件 功能与运用

STL提供六大组件,彼此可以组合套用

容器:vector,deque,list,set,map

算法:sort,search,copy,erase

迭代器:扮演容器和算法之间的胶合剂,是所谓的“泛型指针”

仿函数:行为类似函数,可作为算法的某种策略(policy)。从实现角度来看,仿函数是一种重载operator()的class或class template 。一般函数指针可视为狭义的仿函数。

配接器:一种用来修饰容器或仿函数或迭代器接口的东西。

配置器:负责空间配置和管理。从实现角度来看,配置器是一个实现动态空间配置、管理空间、空间释放的class template。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FxI9zEKm-1692172800971)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220920155957454.png)]

2.对一个类定义前置操作和后置操作

#incldue<iostream>
using namespce std;
//定义INT 类
class INT{
    friend ostream& operator<<(ostream &os,const INT * i);
    public:
    INT(int i):m_i(i);
    //定义前置++ 操作
    INT& operator++(){
        ++(this->m_i);
        return *this;
    }
    //定义后置++ 操作
    INT& operator++(int){
        INT temp=*this;
        ++(*this);
        return temp;
    }
     //定义前置-- 操作
    INT& operator++(){
        --(this->m_i);
        return *this;
    }
    //定义后置-- 操作
    INT& operator++(int){
        INT temp=*this;
        --(*this);
        return temp;
    }
   int& operator*() const{
       return (int &)m_i;
   }
   private:
    int m_i;
};
ostream& operator<<(ostream& os,const INT& i){
    os<<'{'<<i.m_i<<']';
    return os;
}

空间配置器

1.SGI 特殊的空间配置器,std::alloc

class Foo{...};
Foo *pf=new Foo;//调用 opeator new 配置内存 ,在调用Foo:Foo()构造对象内容
delete pf;//先析构,然后用::operator delete释放内存

为了紧密分工,STL allocator将这两阶段操作区开,内存配置操作由alloc::allocate()负责,内存释放由alloc::deallocate()负责;对象构造操作由::construct()负责,对象析构操作由::destory()负责。

SGI内容包含一下两个文件:

#include<stl_alloc.h>//负责内存空间的配置和释放
#include<stl_construct.h>//负责对象内容的构造和析构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9yLRPNFz-1692172800972)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220920183554633.png)]

对象的构造和析构基本工具:construct()和destory()

#include<new.h>
template<class T1,class T2>
inline void construct(T1* p,const T2& value){
new (p) T1(value);
}
//以下是destory()第一版本,接受一个指针
template<class T>
inline void destory(T* pointer){
    pointer->~T;
}
//destory 第二版本,接受两个迭代器
template<class ForwardIterator>
inline void destory(ForwardIterator first,ForwardIterator last){
    _destory(first,last,value_type(first));
}
//判断元素数值类别(value_type)是否由trivial destructor
template<class ForwardIterator,class T>
inline void _destory(ForwardIterator first,ForwardIterator last,T*){
    typedef typename _type_traits<T>::has_trivial_destructor trivial_destructor;
    _destory_aux(first,last,trival_destructor());
}
//数据类型为non_trivial destructor,对所有元素进行析构,
template<class ForwardIterator>
inline void _destory_aux(ForwardIterator first,ForwardIterator last,_false_type){
    for(;first<last;+first)
        destory(&*first);
}
//数据类型为trivial destructor,对不进行析
template<class ForwardIterator>
inline void _destory_aux(ForwardIterator first,ForwardIterator last,_true_type){
}

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

SGI是以malloc()和free()完成内存的配置和释放

当配置区块超过128bytes,视为足够大,直接调用第一级配置器,直接采用malloc()和free()

当配置区块小于128bytes,视为过小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iu7d3EiC-1692172800973)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220921194538433.png)]

无论alloc被定义为第一级配置器还是第二级配置器,SGI还可以为它再包装一个接口,使配置器接口能够复合STL规格

template<class T,class Alloc>
class simple_alloc{
public:
    static T *allocate(size_t n){
        return 0==n? 0:(T*) Alloc::allocate(n*sizeof(T));}
    static T *allocate(void){
        return (T*) Alloc::allocate(sizeof(T));}
    static T * deallocate(T *p ,size_t n){
       if(0!==n) Alloc::deallocate(p,n*sizeof(T));}
    static T *deallocate(T *p){
        Alloc::deallocate(p,sizeof(T));}
    }
    }
}

第一级配置器和第二级配置器的包装接口和运行方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BqH05Mad-1692172800973)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220921194629548.png)]

第一级配置器 __malloc_alloc_template 剖析

template<int inst>
class _malloc_alloc_template{
private:
    //以下都是函数指针,所代表的函数将用来解决内存不足的情况
    //oom: out of memory
    static void  *oom_malloc(size_t);
    static void *oom_realloc(void *,size_t);
    static void (*_malloc_allioc_oom_handler)();

public:
    static void * allocate(size_t n){
        void *result=malloc(n);//第一级配置器直接用malloc()
        //如果无法满足需求时,采用 oom_malloc()
        if(0==result) result=oom_malloc(n);
        return result;
    }
    static void * deallocate(void * p,size_t /* n */){
        free(p);//第一级适配器直接用free
    }
    static * void reallocate(void *p,size_t /* old_sz */,size_t new_sz){
        //realloc:更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小
        void * result=realloc(p,new_sz);
         //如果无法满足需求时,采用 oom_malloc()
        if(0==result) result=oom_malloc(p,new_sz);
        return result;
    }
    
    //以下是仿真c++的set_new_handler(),用它指定自己的out-of-memory handler
    static void (*set_malloc_handler(void (*f)())) (){
        void (* old)()=_malloc_alloc_oom_handler;
        _malloc_alloc_oom_handler=f;
        return (old);
    }
    //malloc_alloc out-of-memory handing,初始值为0,有待客端设定
    template<int inst>
    void (*_malloc_alloc_template<inst>::_malloc_alloc_oom_handler)()=0;
    
    tempalte<int inst>
    void *_malloc_alloc_template<inst>::oom_malloc(size_t n){
        void (* my_malloc_handler)();
        void *result;
        for(;;){//不断尝试释放配置,再释放,再配置...
            my_malloc_handler=_malloc_alloc_oom_handler;
            if(0==my_alloc_handler){_THROW_BAD_ALLOC;}//当内存不足例程未被客端设定,将抛出异常
            {*my_alloc_handler}();//调用处理例程,企图释放内存
            return =malloc(n);  //再次尝试配置内存
            if(result) return (result);
        }
    }
    
    tempalte<int inst>
    void *_malloc_alloc_template<inst>::oom_remalloc(void *p,size_t n){
        void (* my_malloc_handler)();
        void *result;
        for(;;){//不断尝试释放配置,再释放,再配置...
            my_malloc_handler=_malloc_alloc_oom_handler;
            if(0==my_alloc_handler){_THROW_BAD_ALLOC;}
            {*my_alloc_handler}();//调用处理例程,企图释放内存
            return =remalloc(p,n);  //再次尝试配置内存
            if(result) return (result);
        }
    }    
}

第二级配置器 _default_alloc_template 剖析

第二级配置器多一些机制,避免太多小额区间造成内存的碎片。小额区级带来的不仅是内存碎片,配置时额外负担也是大问题。区间越小,额外负担所占比例就越大。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iP9Hg3ea-1692172800973)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220921202431077.png)]

当区块够大,超过128bytes就移交给第一级配置器,当小于128bytes则以内存池(memory pool)管理。称为次层配置:每次配置一大块内存,并维护对应之自由链表。为了方便将内存需量求调整至8的倍数,(客端需要30bytes,自动调整为32bytes),并维护16个free-lists。各自管理大小为8-128bytes。当需要内存时,就用free-lists拔出,释放了由配置器归还到free-lists。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aSTIXzXh-1692172800974)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220921203215244.png)]

//第二级配置器部分实现内容
enum{_ALIGN =8};//小型区块的上调边界
enum{_MAX_BYTES=128}; //小型区块的上限
enum{_NFREELISTS =_MAX_BYTES/_ALIGH}//free_list个数
template<bool threads,int inst>
class _default_alloc_template{
private:
//ROUND_UP 将bytes上调至8的倍数
static size_t ROUND_UP(size_t bytes){
	return (((bytes)+_ALIGN-1)& ~(_ALIGN-1));
}
private :
	union obj{ //free_list的节点构造
	union obk * free_list_link;
	char client_data[1];
	}
private:
//16个free_listes
static obj *volatile free_list[_NFREELISTS];
//以下函数根据区块大小,决定使用第n号free_list.n从1起算
static size_t FREELIST_INDEX(size_t bytes){
return (((bytes)+_ALIGN-1)/_ALIGN-1);
}
//返回大小为n的对象,并可能加入大小为n的其他区块到free list
static void *refill(size_t n);
//配置一大块空间,容纳nobjs个大小为“size"的区块
//如果配置nobjs个区块有所不便,nobjs 可能会降低
static char *chunk_alloc(size_t size,int *nobjs);

//chunk allocation state
static char *start_free; //内存池起始位置,只在chunk_alloc()中变化
static char *end_free; //内存池结束位置,只在chunK_alloc()中变化
static size_t heap_size;

public:
static void * allocate(size_t n){....}
static void deallocate(void *p,size_t)
static size_t heap_size;
}

空间配置函数allocate()

判断区块大小,大于128bytes就调用第一级配置器,小于128bytes就检查对应的free list。如果free list之内由可用的区块,就直接拿来用,如果没有可用的区块,就直接将区块大小上调至8倍数边界,然后调用refill(),准备为free list 重新填充空间

static void * allocate(size_t n){
 obj * volatile * my_free_list;
 obj * result;
 //如果大于128就调用第一级配置器
 if(n>(size_t)_MAX_BYTES){
   return (malloc_alloc::allocate(n));
 }
 //寻找16个free lists中适当的一个
 my_free_list =free_list+FREELIST_INDEX(n);
 result-*my_free_list;
 if(result ==0){
 //没找到可用的free list ,准备填充free list
 void * r=refill(ROUND_UP(n));
 return r;
 }
 //调整free list
 *my_free_list=result->free_list_link;//指向下一个
 return (result); 
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NV5rgz1t-1692172800974)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220921213459043.png)]

空间释放函数dealllocate()

static void * deallocate(void *p,size_t n ){
 obj * q =(obj *)p;
 obj * volatile *my_free_list;
 //如果大于128就调用第一级配置器
 if(n>(size_t)_MAX_BYTES){
   return (malloc_alloc::deallocate(p,n));
 }
 //寻找16个free lists中适当的一个
 my_free_list =free_list+FREELIST_INDEX(n);
 result-*my_free_list;
 //调整free list
 q->free_list_link=*my_free_list;//指向下一个
 *my_free_list=q;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2LCNKC5-1692172800974)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220921214556723.png)]

重新填充free lists

当free list中没有可用的区块,调用refill(),准备为free list 重新填充空间。新的空间将取自内存池(经由chunk_alloc()完成)。
//返回一个大小为n的对象,并且有时候会为适当的free list增加节点
//假设n已经适当上调至8的倍数
template<bool threads,int inst>
void *_default_alloc_template<threads,inst>::refill(size_t n){
     //n 是指要的内存字节大小 可能为8 16 24 
    int nobjs=20; // 指取几块
    //调用chunk_alloc(),尝试取得nobjs 个区块作为free list的新节点
    //注意参数 nobjs 是pass by reference
    char *chunk=chunk_alloc(n,nobjs);
    objs * volatile *my_free_list;
    obj * result;
    obj * current_obj,*next_obj;
    int i;
    //如果只获得一个区块,这个区块就分配调用,free list 无新节点
    if(1==nobjs) return (chunk);
    my_free_list=free_list+PREELIST_INDEX(n);
    //以下再chunk 空间内创建 free list
    result=(obj *)chunk; //这一块准备返回给客端
    //以下导引free list 指向新配置的空间
    *my_free_list=next_obj
    //以下将free list 的个节点串接起来
    for(i=1;;i++){
       
        current_obj=next_obj;
        next_obj=(obj *)((char *)next_obj+n);
        if(nobjs-1==i){
            current_obj->free_list_link=0;
            break;
        }else{
            current_obj->free_list_link=next_obj;
        }
        }
    }
    return (result);
}

内存池(memory pool)

从内存池中取空间给free list使用,是chunk_alloc()的工作:

//假设size 已经适当上调至8的倍数
template<bool threads,int inst>
char * _default_alloc_template<thread ,inst>::chunk_alloc(size_t size,int &nojs){
char * result;
size_t total_bytes=size*nobjs;
size_t bytes_left=end_free_start_free;//内存池剩余空间
if(byetes_left>=toal_bytes){
    //内存池剩余空间完全满足需求量
    result=start_free;
    start_free+=total_bytes;
    return result;
}
else if(bytes_left>=size){
	//内存池剩余空间不能完全满足需求量,但是足够供应一个含以上的区块
	nobjs=bytes_left/size;
	total_bytes=size*nobjs;
	result=start_free;
	start_free+=total_bytes;
	return (result);
}else{
	//内存池剩余空间连一个区块的大小都无法提供
    //从heap中配置内存,要求的内存需求是要配置的2的倍
	size_t bytes_to_get=2*total_bytes+ROUND_UP(heap_size>>4);
	//以下试着让内存池中的残存零头还有剩余价值
	if(bytes_left>0){
		//内存池内还有一些零头,先配给适当的free list
		//首先先寻找适当的free list
		obj * volatile 8 my_free_list=free_list+FREELIST_INDEX[bytes_left];
		//调整free list 将内存池中残余空间插入
		((* obj)start_free)->free_list_link=*my_free_list;
		*my_free_list=(obj *)start_free;
	}
	//配置heap空间,用来补充内存池
	start_free=(char *)malloc(bytest_to_get);
	if(0==statrt_free){
		//heap 空间不足,malloc()失败
		int i;
		obj 8 volatile * my_free_list *p;
		//试着检视我们手上的东西,这不会造成伤害,我们不打算尝试配置较小的区块,因为多进程机器上容易造成灾难
		//以下搜寻适当的free list
		//所谓适当就是 ”尚有未用区块,且区块足够大“知free list
		for(i=size;<_MAX_BYTES;I+=_ALIGN){
			my_free_list=free_list+FREELIST_INDEX(I);
			p=*my_free_list;
			if(0!=p){//free list 内尚有未用的区块
				*my_free_list=p->free_list_link;
				statrt_free=(char *)p;
				end_free=start_free+i;
				return (chunk_alloc(size,nobjs));
			}
		}
		end_free=0;//没有一点内存可以用
		//调用第一级配置器,来看看out-of-momory机制是否可以尽点力
		start_free=(char*)malloc_alloc::allocate()bytest_to_get);
		//这会抛出异常,或者内存不足会情况获得改善
	}
	heap_size+=bytes_to_get;
	end_free=start_free+bytes_to_get;
	return (chunk_alloc(size,nobjs));
}
}

具体流程是,当内存池内空间足够时就将这个调用20个区块返回给free_list(一个交给客端,19个维护)。当内存池空间不足二十个但是大于1个就将不足20的空间交给free_list。如果内存池的空间一个区块的空间都没有,需要利用malloc()从heap中重新配置内存,新配置的内存为需求量的二倍,就是40个区块空间。当整个system heap空间不够时,就去找是否有大于区块但是未用的free list,找到就挖一块交出去,找不到就调用一级配置器,一级配置器有out-of-memory机制,有机会释放其他内存拿来给自己用。如果失败就报异常。

2.内存基本处理工具

uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n(),分别对应高层次函数copy(),fill(),fill_n()。

uninitilaized_copy

template<class InputIterator,class ForwardIterator>
FrowardIterator uninitialized_copy((InputIterator first,InputIterator last,ForwardIterator result);

uninitialized_copy()使将内存配置和对象的构造行为分离开。输入目的地[result,result+(last-first)]范围内每个迭代器都指向未初始化的区域,则uninitialized_copy()会使用copy constructor给身为输入来源[first,last)范围内每个对象产生一份复制品,放入输出范围中。

容器的全局构造函数range constructor以两个步骤完成:

  • 配置内存区块,足以包含范围内所有元素
  • 使用uninitialized_copy(),再该内存上构造元素

uninitialized_fill

template<class InputIterator,class ForwardIterator>
void uninitialized_fill((InputIterator first,InputIterator last,const T&x);

uninitialized_fill()使将内存配置和对象的构造行为分离开。输入目的地**[First,last)]范围内每个迭代器都指向未初始化的区域,则uninitialized_fill()会使用copy constructor给[first,last)范围内每个对象产生一份x复制品**,放入输出范围中。

uninitialized_fill_n

template<class ForwardIterator,class Size,class T>
ForwardIterator uninitialized_fill_n((ForwardIterator first,Size n,const T&x);

uninitialized_fill()使将内存配置和对象的构造行为分离开。输入目的地[first,first+n)范围内每个迭代器都指向未初始化的区域,则uninitialized_fill()会使用copy constructor给[first,first+n)范围内每个对象产生一份x复制品,放入输出范围中。

这三个都是支持回滚的,要不产生所有必要元素,要不不产生任何元素。

这三个函数对于元素类别采用不通的方法创造复制品,对于POD(传统C struct)类型,直接采用复制方法。对于非POD采用构造方法一个一个构造。

//例如**uninitilaized_copy**
template<class InputIterator ,class ForwardIterator,class T>
inline ForwardIterator _uninitialized_copy(InputIterator first,InputIterator last,ForwardIteratro result,T*){
typedef typename _type_trait<T>::is_PO_type is_POD;
return _uninitalized_copy_aux(first,last,result,is_POD());
}
//POD类型
template<class InputIterator ,class ForwardIterator>
inline ForwardIterator uninitalized_copy_aux(InputIterator first,InputIterator last,ForwardIteratro result,_true_type){
return copy(first,last,result,result);
}
//非POD类型
template<class InputIterator ,class ForwardIterator>
inline ForwardIterator uninitalized_copy_aux(InputIterator first,InputIterator last,ForwardIteratro result,_false_type){
ForwardIterator cur=reslut;
for(;first!=last;++first;++cur)
    construct(&*cur,&first);
    return cur;
}

三个内存基本函数的泛型版本与特化版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M2DuaYkY-1692172800975)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220922153942962.png)]

迭代器

STL的中心思想是将数据容器和算法分开,彼此独立设计,最后再以一贴粘合剂将它们撮合在一起。迭代器就是粘合剂。

1.迭代器相应型别

如果想在算法中申明一个变量,以”迭代器所指对象的型别“

直接用function template 参数推导机制

template <class I,class T>
void func_impl(I iter,T t){
	T temp;// 定义参数
	//..这里做func()应该做的事
};
template<class I>
inline void func(I iter){
func_impl(iter,*iter);
}
int main(){
    int i;
    func(& i);
}

但是对于指定返回值类型就不行了,因为template 参数推导不能推导返回值类型

采用声明嵌套类的方法

template<class T>
struct MyIter{
    typedef T value_type;//内嵌申明
    T* ptr;
    MyIter(T* p=0):ptr(p){}
    T& operator*() const {return *ptr;}
    //...
};
template<class T>
typename I::valye_type func(I iter){
    return *iter;
}
//...
MyIter<int> ite(new int(8));
cout<<func(ite);

但是不是所有的迭代器都是 class type,对于非class 无法在内部定义

采用template partial specialization

//将这个类型的定义写在外面
//traits 扮演特性萃取机的角色,这个特性s就是迭代器相应类别
template<class I>
struct iterator_traits<I *>{
typedef I value_type;
}
//针对指向常数对象的指针
template<class T>
strcut iteraotr_traits<const T*>{
    typedef T value_type;
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FHCbCvR-1692172800975)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220922170357965.png)]

常用迭代器相应类别有五种:value type,difference type,pointer,reference,iterator catagoly

iterator_traits负责萃取迭代器的特性

template<class I>
struct iterator_traits{
	typedef typename I::iterator_category iterator_category;
	typedef typename I::value_type value_type;
	typedef typename I::difference_type difference_type;
	typedef typename I::pointer pointer;
	typedef typename I::refernce;
}

value type

value type 是指迭代器所指对象的类型

difference type

difference type 用来表示两个迭代器之间的距离,用来表达一个容器的最大容量

reference type

int *pi=new int(5);
const int 8pci=new int(90);
*pi=7; //对mutable iterator 进行解引用,获得是一个左值,允许赋值
*pci=1;//不容许 ,pci是一个constant iterator

p是mutable iterator其value type是T,但是P是T&,p如果是一个constant iterator其value type是T,但是P是 const T&;这就是 reference type

point type

Item& operator*() const{return *ptr;}
Item* operator->() const{return ptr;}
//Item& 是reference type,Item* 是point type

iterator_category

定义的是iterator的类别。

Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator,Random Access Iterator

直线和箭头并非c++的继承关系 而是concept(概念)与refinement(强化)的关系。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QFVqYiEU-1692172800975)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220922191320119.png)]

//对于迭代器函数例如 distance()不同的迭代器有不同的实现方式,因此需要用标明迭代器的类型去针对不同迭代器 选择不同实现
struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag:public input_iterator_tag{};
struct bidirectional_iterator_tag:public forward_iterator_tag{};
struct random_access_iterator_tag:public bidirectional_iterator_tag{};
//不同迭代器实现advance
//Inputator
template<class InputIterator ,class Distance>
inline void _advance(InputIterator& i,Distance n,input_iterator_tag){
    while(n--) ++i;
}
//RandomAccessIterator
template<class RandomAccessIterator ,class Distance>
inline void _advance(RandomAccessIterator& i,Distance n,random_access_iterator_tag){
    i=+n;
}
//advnace 对外上层接口,以Iterator 为模板参数是STL算法的一个命名规则,算法所能接受之最低阶迭代器类型来为迭代器型别参数命名。
template<class InputIterator,class Distance>
inline void advance(InputIterator& i,Distance n){
    _advance(i,n,iterator_traits<InputIterator>::iterator_category());
}

2.__type_traits

_type_traits负责萃取型别特性

对于uninitilaized_copy,uninitialized_fill,uninitialized_fill_n针对不同的类型采用不同的构造方法。

struct _true_type{};//定义成结构体是为可以直接从名字看出 它表达的意思
struct _flase_type{};
//因此在type_traits中定义一些typedefs,其类型不是_true_type就是_false_type
template <class type>
struct _type_traits{
    typedef _true_type this_dummy_member_must_be_first;//它是通知有能力自动将_type_traits特化的编译器说,我们现在看到这个_type_traits template是特殊的
    //默认全是_flase_type
    typedef _false_type has_trivial_default_constructor;
    typedef _false_type has_trivial_copy_constructor;
    typedef _false_type has_trivial_assignment_operator;
    typedef _false_type has_trivial_destructor;
    typedef _false_type is_POD_type;
}

对于一些基本类型提出特化_type_traits

//例如char
_STL_TEMPLATE_NULL struct _type_traits<char>{
	typedef _true_type has_trivial_default_constructor;
    typedef _true_type has_trivial_copy_constructor;
    typedef _true_type has_trivial_assignment_operator;
    typedef _true_type has_trivial_destructor;
    typedef _true_type is_POD_type;
}

实际使用

template<class InputIterator ,class ForwardIterator,class T>
inline ForwardIterator _uninitialized_copy(InputIterator first,InputIterator last,ForwardIteratro result,T*){
typedef typename _type_trait<T>::is_PO_type is_POD;
return _uninitalized_copy_aux(first,last,result,is_POD());
}

序列式容器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-27BK8IFU-1692172800975)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220925201623294.png)]

1.vector

vecot源码摘录

template<class T,class Alloc * alloc>
class vecotr{
	public:
	//vector的嵌套型别定义
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type* iterator;
	typedef value_type& reference;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	protected:
	typedef simple_alloc<value_type,Alloc> data_allocator;
	iterator start; //表示目前使用空间的头
	iterator finish; //表示目前使用空间的尾
	iterator end_of_storage; //表示目前可用空间的尾;
	
	void insert_aux(iterator poisition,const T& x);
	void deallocate(){
	if(start)
		deallocator::deallocate(start,end_of_storage-start);
	}
	
	void fill_initalize(size_type n,const T& value){
		start=allocate_end_fill(n,value);
		finish=start+n;
		end_of_storage=finish;
	}
	public:
	iterator begin() {return start;}
	ierator end() {return finish;}
	size_type size() const {return size_type(end()-begin());}
	size_type capacity() const{
		return size_type(end_of_storage-begin());}
	bool empty() const {return begin()==end();}
	reference operator[](size_type n){reutrn *(begin()+n);}
    
    vector():start(0),finish(0),end_of_storage(0){}
    vector(size_type n,const T& value){fill_initialzie(n,value);}
    vector(int n,const T&value){fill_initilaize(n,value);}
    vector(long n,const T&value){fill_initilaize(n,value);}
    explicit vector(size_type n){fill_initialize(n,T());}
    
    ~vector(){
        destory(start,finish);
        deallocate();
    }
    reference front() {return *begin();}
    reference back() {return *(end()-1);}
    void push_back(const T&x){
        if(finish!=end_of_storage){
            construct(finish,x);
            ++finish;
        }
        else
            insert_aux(end(),x);
    }
   void pop_back(){
       --finish;
       destroy(finish);
   }
   iterator erase(iterator position){
       if(position+1!=end())
           	copy(position+,finish,position);
       --finish;
       destory(finish);
       return position;
   }
   void resize(size_type new_size,const T&x){
       if(new_size<size())
           erase(negin()+new_size,end());
       else
           insert(end(),new_size-size(),x);
   }
    void resize(size_type new_size){resize(new_size,t());}
    void clear() {erase{begin(),end()};}
	}
	protected:
	iterator allocate_and_fill(size_type n,const T& x){
        ierator result =data_allocator::allocate(n);
        uninitalizeed_fiil_n(result,n,x);
        return result;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-53OW6lLM-1692172800976)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220925213451685.png)]

vecotr 内存扩张代码

//vecotr 内存扩张代码
template<class T,class Alloc>
void vecotr<T,Alloc>::insert_aux(iterator position,const T& x){
	if(finish!=end_of_storage){//还有备用空间
	//在备用空间起始位置构造一个元素,并以vector最后一个元素指为初始值
	construct(finish,*(finish-1));
	++finish;
	T x_copy =x;
	copy_backward(position,finish-2,finish-1);
	*position =x_copy;
	}
	else{//无备用位置
		//并不是在原来的位置接续新空间,而是找一块大的空间,将原来的元素复制过来,
		//因此对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。
		const size_type old_size=size();
		const size_type len=lod_size!=0? 2*len:1;
		iterator new_start =data_allocator::allocate(len);//实际配置
		iterator new_finish=new_start;
		try{
			new_finish=uninitilaized_copy(start,position,new_start);
			construct(new_finish,x);
			++new_finish;
			new_finish=uninitialized_copy(position,finish,new_finish);
		}
		catch(...){
			//支持回滚
			destory(new_start,new_finish)
			data_allocator::deallocate(new_start,len);
            throw;
		}
		//析构并并释放原来vecotr
		destory(begin(),end());
		deallocate();
		//调整迭代器,指向新vector
		start=new_start;
		finsih=new_finish;
		end_of_stroage=new_start_len;
	}
}

vector::insert()实现内容

template<class T,class Alloc>
void vector<T,Alloc>::insert(iterator position,size_type n,const T&x){
    if(n!=0){
        if(size_type(end_of_storage-finish)>=n){
            T x_copy=x;
            const size_type elems_after=finish-position;
            iterator old_finish=finish;
            if(elems_after>n){
                //插入节点之后的现元素的个数大于新增元素个数
                uninitalized_copy(finish-m,finish,finish);
                finish+=n;
                copy_backward(position,old_finish-n,old_finish);
                fill(position,position+x,x_copy);
            }else{//备用空间小于新增元素个数
                //首先决定新长度,旧长度的两倍,或旧长度+新增元素个数
                const size_type old_size=size();
                const size_type len=old_size+max(old_size,n);
                iterator new_start=data_allocator::allocate(len);
                iterator new_finish=new_start;
                _STL_TRY{
                    new_finsih=uninitialized_copy(start,position,new_start);
                    new_finish=uninitialized_fill_n(new_finish,n,x);
                    new_finish=uninitialized_copy(position,finish,new_finish);
                }
                catch(...){//回滚
                    destory(new_start,new_finish)
					data_allocator::deallocate(new_start,len);
           			 throw;
                }
                destory(start,finish);
                deallocate();
                start=new_start;
                finish=new_finish;
                end_of_storage=new_start+len;
            }
        }
    }
}

关联式容器

算法

仿函数

            const size_type len=old_size+max(old_size,n);
            iterator new_start=data_allocator::allocate(len);
            iterator new_finish=new_start;
            _STL_TRY{
                new_finsih=uninitialized_copy(start,position,new_start);
                new_finish=uninitialized_fill_n(new_finish,n,x);
                new_finish=uninitialized_copy(position,finish,new_finish);
            }
            catch(...){//回滚
                destory(new_start,new_finish)
				data_allocator::deallocate(new_start,len);
       			 throw;
            }
            destory(start,finish);
            deallocate();
            start=new_start;
            finish=new_finish;
            end_of_storage=new_start+len;
        }
    }
}

}




## 关联式容器

## 算法

## 仿函数

## 配接器
神书-STL实现原理,对于强化数据结构-算法的程序员必备、必读书籍。The Best-Selling Programmer Resource–Now Updated for C++11 The C++ standard library provides a set of common classes and interfaces that greatly extend the core C++ language. The library, however, is not self-explanatory. To make full use of its components - and to benefit from their power - you need a resource that does far more than list the classes and their functions. The C++ Standard Library - A Tutorial and Reference, 2nd Edition describes this library as now incorporated into the new ANSI/ISO C++ language standard (C++11). The book provides comprehensive documentation of each library component, including an introduction to its purpose and design; clearly written explanations of complex concepts; the practical programming details needed for effective use; traps and pitfalls; the exact signature and definition of the most important classes and functions; and numerous examples of working code. The book focuses on the Standard Template Library (STL), examining containers, iterators, function objects, and STL algorithms. You will also find detailed coverage of strings, concurrency, random numbers and distributions, special containers, numerical classes, internationalization, and the IOStreams library. An insightful introduction to fundamental concepts and an overview of the library will help bring newcomers quickly up to speed. A comprehensive index will support the C++ programmer in his/her day-to-day life.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

onnx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值