STL的框架实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL的框架实现相关的知识,希望对你有一定的参考价值。

1、模板的特化

    泛化模板 : 对各种不同版本的特殊化处理---->特化;

2、萃取

    拿相同的代码提取不同的类型;

3、整个搭建框架如下:

技术分享

    在这里已经不关心空间配置器是如何实现的;

    其框架代码如下:

#ifndef _MEMORY_H_
#define _MEMORY_H_

#include"stl_alloc.h"
#include"stl_iterator.h"
#include"type_traits.h"
#include"stl_construct.h"
#include"stl_uninitialized.h"

#endif
////////////////////////////////////////////////////////////////////////////////////

#if 1
#include<iostream>
#include<new>
#include<malloc.h>
using namespace std;
//#define __THROW_BAD_ALLOC   throw   bad_alloc
#define __THROW_BAD_ALLOC  cerr<<"Throw bad alloc, Out Of Memory."<<endl; exit(1)
#elif  !defined  (__THROW_BAD_ALLOC)
#include<iostream.h>
#define __THROW_BAD_ALLOC   cerr<<"out of memory"<<endl; exit(1);
#endif

template<int inst>
class __malloc_alloc_template{
private:
    static void* oom_malloc(size_t);
    static void* oom_realloc(void *, size_t);
    static void(* __malloc_alloc_oom_handler)();

public:
    static void* allocate(size_t n){
        void *result = malloc(n);
        if(0 == result){
            result = oom_malloc(n);
        }
        return result;
    }
    static void   deallocate(void *p, size_t){
        free(p);
    }
    static void* reallocate(void *p, size_t, size_t new_sz){
        void *result = realloc(p, new_sz);
        if(0 == result){
            oom_realloc(p,new_sz);
        }
        return result;
    }
public:
    //set_new_handler(Out_Of_Memory);
    static void(*set_malloc_handler(void(*f)()))(){
        void(*old)() = __malloc_alloc_oom_handler;
        __malloc_alloc_oom_handler = f;
        return old;
    }
};

template<int inst>
void (*__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;

template<int inst>
void* __malloc_alloc_template<inst>::oom_malloc(size_t n){
    void *result;
    void(* my_malloc_handler)();

    for(;;){
        my_malloc_handler = __malloc_alloc_oom_handler;
        if(0 == my_malloc_handler){ 
            __THROW_BAD_ALLOC;
        }
        (*my_malloc_handler)();
        result = malloc(n);
        if(result){
            return result;
        }
    }
}


template<int inst>
void* __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n){
    void(*my_malloc_handler)();
    void *result;
    for(;;){
        my_malloc_handler = __malloc_alloc_oom_handler;
        if(0 == my_malloc_handler){
            __THROW_BAD_ALLOC;
        }
        (*my_malloc_handler)();
        result = realloc(p, n);
        if(result){
            return result;
        }
    }
}

typedef __malloc_alloc_template<0> malloc_alloc;

/////////////////////////////////////////////////////////////////////////////////////

enum {__ALIGN = 8};
enum {__MAX_BYTES  = 128};
enum {__NFREELISTS = __MAX_BYTES / __ALIGN};

template<bool threads, int inst>
class __default_alloc_template{
public:
    static void* allocate(size_t n);
    static void  deallocate(void *p, size_t n);
    static void* reallocate(void *p, size_t, size_t new_sz);
private:
    static size_t  ROUND_UP(size_t bytes){
        return (((bytes) + __ALIGN-1) & ~(__ALIGN-1));
    }
private:
    union obj{
        union obj * free_list_link;
        char client_data[1];
    };
private:
    static obj* volatile free_list[__NFREELISTS];
    static size_t FREELIST_INDEX(size_t bytes){
        return ((bytes)+__ALIGN-1) / __ALIGN-1;
    }
private:
    static char *start_free;
    static char *end_free;
    static size_t heap_size;
    static void *refill(size_t n);
    static char* chunk_alloc(size_t size, int &nobjs);
};


template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::start_free = 0;
template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::end_free = 0;
template<bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0;
template<bool threads, int inst>
typename __default_alloc_template<threads, inst>::obj* volatile
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] = 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

template<bool threads, int inst>
void* __default_alloc_template<threads, inst>::allocate(size_t n){
    obj * volatile *my_free_list;
    obj *result;

    if(n > __MAX_BYTES){
        return malloc_alloc::allocate(n);
    }

    my_free_list = free_list + FREELIST_INDEX(n);
    result = *my_free_list;

    if(result == 0){
        void *r = refill(ROUND_UP(n));
        return r;
    }

    *my_free_list = result->free_list_link;
    return result; 
}

template<bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n){
    int nobjs = 20;
    char *chunk = chunk_alloc(n, nobjs);
    obj * volatile *my_free_list;

    obj *result;
    obj *current_obj, *next_obj;
    int i;

    if(1 == nobjs){
        return chunk;
    }

    my_free_list = free_list + FREELIST_INDEX(n);
    result = (obj*)chunk;
    *my_free_list = next_obj = (obj*)(chunk+n);

    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;
}

template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int &nobjs){
    char *result;
    size_t total_bytes = size * nobjs;
    size_t bytes_left = end_free - start_free;
    if(bytes_left >= total_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{
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        if(bytes_left > 0){
            obj * volatile * my_free_list = free_list + FREELIST_INDEX(bytes_left);
            ((obj*)start_free)->free_list_link = *my_free_list;
            *my_free_list = (obj *)start_free;
        }

        start_free = (char *)malloc(bytes_to_get);
        if(0 == start_free){
            int i;
            obj * volatile *my_free_list, *p;
            for(i=size; i<=__MAX_BYTES; i += __ALIGN){
                my_free_list = free_list + FREELIST_INDEX(i);
                p = *my_free_list;
                if(0 != p){
                    *my_free_list = p->free_list_link;
                    start_free = (char *)p;
                    end_free = start_free + i;
                    return chunk_alloc(size, nobjs);
                }
            }
            end_free = 0;
            start_free = (char *)malloc_alloc::allocate(bytes_to_get);
        }

        heap_size  += bytes_to_get;
        end_free = start_free + bytes_to_get;
        return chunk_alloc(size, nobjs);
    }
}

/////////////////////////////////////////////////////////////////////////////////
#ifdef __USE_MALLOC
typedef malloc_alloc  alloc;
#else
typedef __default_alloc_template<0,0> alloc;
#endif

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 void deallocate(T *p, size_t n){
        if(0!=n) Alloc::deallocate(p, n*sizeof(T));
    }
    static void deallocate(T *p){
        Alloc::deallocate(p,sizeof(T));
    }
};
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef __STL_CONFIG_H
#define __STL_CONFIG_H

//#define __USE_MALLOC


#endif

//////////////////////////////////////////////////////////////////////////////////////////

#ifndef __STL_CONSTRUCT_H
#define __STL_CONSTRUCT_H

template <class T1, class T2>
void construct(T1* p, const T2& value){
      new (p) T1(value);
}

#endif
////////////////////////////////////////////////////////////////////////////////////////
#ifndef __STL_ITERATOR_H
#define __STL_ITERATOR_H

template <class T>
T* value_type(const T*){
    return (T*)(0); 
}

#endif
////////////////////////////////////////////////////////////////////////////////////////
#ifndef __STL_UNINITIALIZED_H
#define __STL_UNINITIALIZED_H


template<class ForwardIterator, class Size, class T>
ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first, Size n, 
                                                const T &x, _true_type){
    cout<<"yyyyyyyyyyy"<<endl;
    return fill_n(first, n, x);
}

template<class ForwardIterator, class Size, class T>
ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first, Size n, 
                                            const T &x, _false_type){
    ForwardIterator cur = first;
    for(; n>0; --n, ++cur){
        cout<<"xxxxxxxxxxxx"<<endl;
        construct( &*cur, x); //construct(cur, x);
    }
    return cur;
}


template<class ForwardIterator, class Size, class T, class T1>
ForwardIterator _uninitialized_fill_n(ForwardIterator first, Size n, const T &x,  T1*){
    //typedef _false_type  is_POD;
    typedef typename _type_traits<T1>::is_POD_type   is_POD;
    //return _uninitialized_fill_n(first, n, x, _false_type());
    return _uninitialized_fill_n_aux(first, n, x, is_POD());
}

template<class ForwardIterator, class Size, class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T &x){
    return _uninitialized_fill_n(first, n, x, value_type(first));
}

#endif
////////////////////////////////////////////////////////////////////////////////////////
#ifndef __STL_VECTOR_H
#define __STL_VECTOR_H

template<class T, class Alloc=alloc>
class vector{
public:
    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;
public:
    vector() : start(0), finish(0), end_of_storage(0){}
    vector(size_type n){
        fill_initialize(n, T());
    }
protected:
    void fill_initialize(size_type n, const T &value){
        start = allocate_and_fill(n, value);
        finish = start + n;
        end_of_storage = finish;
    }
    iterator allocate_and_fill(size_type n, const T &x){
        iterator result = data_allocator::allocate(n);
        uninitialized_fill_n(result, n, x);
        return result;
    }
protected:
    typedef simple_alloc<value_type, Alloc> data_allocator;
    iterator start;
    iterator finish;
    iterator end_of_storage;
};


#endif
////////////////////////////////////////////////////////////////////////////////////////
#ifndef __TYPE_TRAITS_H
#define __TYPE_TRAITS_H


//

struct _true_type {};
struct _false_type{};

template <class type>
struct _type_traits { 
    typedef _true_type     this_dummy_member_must_be_first;
    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;
};

template<>
struct _type_traits<int> {
    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;
};

#endif
///////////////////////////////////////////////////////////////////////////////////////
#ifndef _VECTOR_H_
#define _VECTOR_H_

#include"memory.h"
#include"stl_vector.h"

#endif
///////////////////////////////////////////////////////////////////////////////////////

测试代码

#include<iostream>
#include<stdlib.h>
#include"vector.h"
using namespace std;

class Test{};

int main(){
    vector<Test> v(10);  //开辟了10个元素的空间;
    return 0;

测试结果

技术分享


4、分析

    (1)、vector的空间灵活性更高;

    (2)、POD:也就是标量型别,也就是传统的型别,采取最保险安全的做法,调用构造函数;否则的话,就是调用系统的,基本类型就是true;

    (3)、空构造了2个类型,针对不同萃取得到其_false_type或_true_type ; 就可以调用不同的函数,进行空间的分配,存在效率上的差异!!!

    _true_type:将调用系统的填充函数,效率比较高.

    (4)、容器、算法单独好实现,关键是通用性,模板是一种很好的解决方案,真正关键之处还在 : 迭代器的实现;

    (5)、空间配置器负责分配、回收空间,只有一个;迭代器针对不同的容器有不同的实现方法!!!

本文出自 “11586096” 博客,请务必保留此出处http://11596096.blog.51cto.com/11586096/1844045

以上是关于STL的框架实现的主要内容,如果未能解决你的问题,请参考以下文章

比给定值最小的最大元素的 STL 算法

text 来自Codyhouse框架的Browserlist片段源代码

STL容器自定义内存分配器

STL容器自定义内存分配器

STL容器自定义内存分配器

STL之list学习&模拟实现