sgi 之vector

最简单的sgi vector竟然写了四五天。

这次编写所暴露的问题是:

1. 一定要单元测试,否则在最后差错的时候会崩溃的

2. 写代码一定要仔细,记住,要bugfree


ccconstruct.h

#ifndef C_CONSTRUCT_H
#define C_CONSTRUCT_H
#include <iostream>
#include <new.h>

inline void destroy(char *, char *){}
inline void destroy(int *, int *){}
inline void destroy(long *, long *){}
inline void destroy(float *, float *){}
inline void destroy(double *, double *){}

//对于int* p,也可以调用这个函数,比较怪异
template <class T>
inline void destroy(T* pointer) {
    pointer->~T();
}

template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
    for (; first  < last ; ++first)
        destroy(first);
}

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

#endif

calloc.h

#ifndef C_ALLOC_H
#define C_ALLOC_H
#include <stdio.h>
#include <stdlib.h>

enum {ALIGN = 8};//
enum {MAX_BYTES = 128};
enum {NFREELISTS = 16};


#define __THROW_BAD_ALLOC std::cerr << "out of memory " <<std::endl; exit(1)
//第一级配置器
template <int inst>//这个模板参数在单线程中没有用,主要用于多线程。__malloc_alloc_template<0>,__malloc_alloc_template<1>就实例化出两个不同的类,可以用于两个不同的线程中,这样既不用加锁也不会减速
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_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 /*old size*/, size_t new_sz) {
        void *result = realloc(p,new_sz);
        if (0 == result) return oom_realloc(p, new_sz);
        return result;
    }

    static void (* set_malloc_handler (void (*f)())) () { //set_malloc_handler是一个函数,其参数是一个函数指针,其返回值也是一个函数指针。这地方要好好揣摩。如果将set_malloc_handler (void (*f)()) 看做p,则就是 (*p)(),set_malloc_handler的返回值就是p
        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 (* 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 = 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;
//第二级配置器

template <bool threads, int inst>
class __default_alloc_template {
private:
    //bytes上调至8的倍数
    static size_t ROUND_UP(size_t bytes) {
        return ( (bytes + ALIGN -1) & ~(ALIGN - 1));
    }

private:
    union obj {
        union obj * free_list_link;
    };
private:
    static obj * free_list[NFREELISTS];
    static size_t FREELIST_INDEX(size_t bytes) {
        return ( (bytes + ALIGN -1)/ALIGN -1);
    }

    //当freelist中没有大小为n个块,调用此函数,会返回从内存池中返回若干个块,将其中的一个返回,将剩余的放入freelist中
    static void *refill(size_t n);

    //从内存池中分配一大块空间,大小为nobjs个大小为 size的块,如果内存不足,nobjs会减小
    static char *chunk_alloc(size_t size, int &nobjs);

    static char *start_free;//内存池起始位置
    static char *end_free;//内存池结束位置

    static size_t heap_size;//一个不太重要的变量

public:
    
    static void * allocate(size_t n) {
        obj ** 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;
    }

    static void deallocate(void *p, size_t n) {
        obj * q = (obj *) p;
        obj ** my_free_list;
        if (n >MAX_BYTES) {//对于大块就free,对于小块是要回收到freelist中,以备再次使用
            malloc_alloc::deallocate(p,n);
            return;
        }

        my_free_list = free_list + FREELIST_INDEX(n);
        q->free_list_link = *my_free_list;
        *my_free_list = q;
    }
    static void * reallocate(void *p, size_t old_sz, size_t new_sz) {
        void * result;
        size_t copy_sz;

        if (old_sz > MAX_BYTES && new_sz > MAX_BYTES) {
            return (malloc_alloc::reallocate(p,old_sz, new_sz));
        }

        if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return p;

        result = allocate(new_sz);
        copy_sz = new_sz > old_sz ? old_sz : new_sz;
        memcpy(result, p , copy_sz);
        deallocate(p, old_sz);
        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 ** 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 (int i = 1;; ++i) {
        current_obj = next_obj;
        next_obj = (obj *)((char *)next_obj + n);
        if (i == nobjs - 1) {
            current_obj->free_list_link = NULL;
            break;
        }
        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){//至少能提供一个块
        result = start_free;
        nobjs = bytes_left / size;
        total_bytes = size * nobjs;
        start_free += total_bytes;
        return result;
    }
    else {
        size_t bytes_to_get = 2 * total_bytes +ROUND_UP(heap_size >> 4);//ROUND_UP(heap_size >> 4)作用不大
        if (bytes_left >0) {
            obj ** 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) {//没有多余内存,需要从freelist中找到块
            int i;
            obj ** 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);
    }
}

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;

//注意一定要有typename告诉编译器,这个模板类肯定有这个类型obj
template<bool threads, int inst>
typename __default_alloc_template<threads, inst>::obj * 
__default_alloc_template<threads, inst>::free_list[NFREELISTS] = 
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

typedef __default_alloc_template<false, 0> alloc;

template<class T, class Alloc>
class simple_alloc {
public:
    //返回n个T大小的内存
    static T *allocate(size_t n) {
        return 0 == n ? 0 : (T *) Alloc::allocate(n * sizeof(T));
    }
    static T *allocate() {
        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));
    }
};


#endif

cvector.h


#ifndef C_VECTOR_H
#define  C_VECTOR_H

#include "calloc.h"
//#include "stl_construct.h"
#include <iostream>
#include <memory>
#include "cconstruct.h"

using namespace std;

template <class T, class Alloc = alloc>
class cvector {
public:
    typedef T value_type;
    typedef value_type* pointer;
    typedef value_type* iterator;
    typedef value_type& reference;
    typedef const value_type* const_iterator;

protected:
    typedef simple_alloc<value_type, Alloc> data_allocator;
    iterator start;
    iterator finish;
    iterator end_of_storage;

    void insert_aux(iterator position, const T& x);
    //这仅是释放vector所占内存,不是析构函数
    void deallocate() {
        if (start)
            data_allocator::deallocate(start, end_of_storage - start);
    }
    
    iterator allocate_and_fill(size_t n, const T& x) {
        iterator result = data_allocator::allocate(n);//获得生内存
        uninitialized_fill_n(result, n, x);//uninitialized_* 之类的函数都是用于生内存的操作,效率较高
        return result;
    }

    void fill_initialize(size_t n, const T& value) {
        start = uninitialized_fill_n(n, value);
        finish = start + n;
        end_of_storage = finish;
    }

    iterator allocate_and_copy(size_t n, const_iterator first, const_iterator last) {
        iterator result = data_allocator::allocate(n);
        uninitialized_copy(first, last, result);
        return result;
    }

public:
    iterator begin() { return start; }
    iterator end() { return finish; }
    size_t size() const { return finish - start; }
    size_t capacity() const { return end_of_storage - start; }
    bool empty() const { return start == finish; }
    reference operator [] (size_t n) { return *(start + n);}
    cvector() :start(0), finish(0), end_of_storage(0) {}
    cvector(size_t n, const T& x) { fill_initialize(n,x); }
    explicit cvector(size_t n) { fill_initialize(n, T()); }
    cvector(cvector<T, Alloc>& x) {
        start = allocate_and_copy(x.size(), x.begin(), x.end());
        finish = end_of_storage = start + x.size();
    }
    void swap(cvector<T, Alloc>& x) {
        std::swap(start, x.start);
        std::swap(finish, x.finish);
        std::swap(end_of_storage, x.end_of_storage);
    }
    void insert(iterator position, size_t n, const T& x);
    void resize(size_t new_sz, const T& x) {
        if (new_sz < size()) {
            erase(begin() + new_sz, end());
        }
        else
            insert(end(), new_sz - size(), x);
    }
    cvector<T, Alloc>& operator=(const cvector<T, Alloc>& x);
    void resize(size_t new_sz) {
        resize(new_sz, T());
    }

    ~cvector() {
        destroy(start, finish);
        deallocate();
    }

    reference front() { return *start; }
    reference back() { return *(finish - 1);}
    
    void push_back(const T& x) {
        if (finish != end_of_storage) {
            construct(finish, x);
            ++finish;
        }
        else {
            insert_aux(end(), x);
        }
    }

    iterator insert(iterator position, const T& x) {
        size_t n = position - start;
        if (finish != end_of_storage && position == finish()) {
            construct(finish, x);
            ++finish;
        }
        else
            insert_aux(position, x);

        return begin() + n;

    }

    void pop_back() {
        --finish;
        destroy(finish);
    }

    iterator erase(iterator position) {
        if (position + 1 != finish)
            copy(position+1, finish, position);
        --finish;
        destroy(finish);
        return position;
    }

    iterator erase(iterator b, iterator e) {        
        iterator i = copy(e, finish, b);
        destroy(i, finish);
        finish -= e - b;
        return b;
    }
    void clear() {
       erase(start, finish);
    }


};

template <class T, class Alloc>
inline bool
operator==(const cvector<T, Alloc>& x, const cvector<T, Alloc>& y) {
    return (x.size() == y.size()) && (equal(x.begin(), x.end(), y.begin()));
}

template <class T, class Alloc>
inline bool
operator<(const cvector<T, Alloc>& x, const cvector<T, Alloc>& y) {
    return lexicographical_compare(x.begin(), x.end(),
                                   y.begin(), y.end());
}

template <class T, class Alloc>
inline bool
operator!=(const cvector<T, Alloc>& x, const cvector<T, Alloc>& y) {
    return !(x == y);
}

template <class T, class Alloc>
inline bool
operator>(const cvector<T, Alloc>& x, const cvector<T, Alloc>& y) {
    return y < x;
}

template <class T, class Alloc>
inline bool
operator<=(const cvector<T, Alloc>& x, const cvector<T, Alloc>& y) {
    return !(y < x);
}

template <class T, class Alloc>
inline bool
operator>=(const cvector<T, Alloc>& x, const cvector<T, Alloc>& y) {
    return !(x < y);
}

template<class T, class Alloc>
cvector<T, Alloc>& cvector<T, Alloc>::operator=(const cvector<T,Alloc> &x) {
    if (&x != this) {
        size_t len = x.size();
        if (len > capacity()) {
            iterator tmp = allocate_and_copy(len, x.begin(), x.end());
            destroy(start, finish);
            deallocate();
            start = tmp;
            finish = start + len;
            end_of_storage = finish;
        }
        else if (size() >= len) {
            iterator tmp = copy(x.begin(), x.end(), start);
            erase(tmp, end());
            finish = tmp;
        }
        else {
            finish = copy(x.begin(), x.begin() + size(), start);
            finish = uninitialized_copy(x.begin() + size(), x.end(), finish);
        }
    }
}

template<class T, class Alloc>
void cvector<T,Alloc>::insert_aux(iterator position, const T &x) {
    if (finish != end_of_storage) {
        //这里要考虑为什么不直接copy_backward(position, finish, finish+1)
        //这是因为原vector的最后一个元素要向后移动一个地址,而这个新的地址上没有对象,所以直接construct就行了,这样效率最高,就只有这个新地址不需要析构
        construct(finish, *(finish - 1));
        ++finish;
        copy_backward(position, finish - 2, finish - 1);
        *position = x;
    }
    else {
        size_t old_sz = size();
        size_t len = old_sz !=0 ? 2 * old_sz : 1;
        iterator new_start = data_allocator::allocate(len);
        iterator new_finish = new_start;

        try {
            new_finish = uninitialized_copy(start, position, new_start);
            construct(new_finish, x);
            ++new_finish;
            new_finish = uninitialized_copy(position , finish, new_finish);
            
        }
        catch (...) {
            destroy(new_start, new_finish);
            data_allocator::deallocate(new_start, len);
            throw;
        }

        destroy(begin(), end());
        deallocate();

        start = new_start;
        finish = new_finish;
        end_of_storage = start + len;
    }
}

template<class T, class Alloc>
void cvector<T, Alloc>::insert(iterator position, size_t n, const T &x) {
    if (n != 0) {
        if (end_of_storage - finish >= n) {
            size_t elems_after = finish - position;
            iterator old_finish = finish;
            if (elems_after > n) {
                uninitialized_copy(finish - n, finish, finish);
                finish += n;
                copy_backward(position, old_finish - n, old_finish);
                fill(position, position + n, x);
            }
            else {
                uninitialized_fill_n(finish, n - elems_after, x);
                finish += n - elems_after;
                uninitialized_copy(position,old_finish, finish);
                finish += elems_after;
                fill(position, old_finish, x);
            }
        }
        else {
            size_t old_sz = size();
            size_t len = old_sz + max(old_sz, n);
            iterator new_start = data_allocator::allocate(len);
            iterator new_finish = new_start;

            new_finish = uninitialized_copy(begin(), position, new_start);
            uninitialized_fill_n(new_finish, n, x);
            new_finish += n;
            new_finish = uninitialized_copy(position, end(), new_finish);

            destroy(start, finish);
            deallocate();

            start = new_start;
            finish = new_finish;
            end_of_storage = start + len;

        }
    }
}

#endif


测试代码:

 cvector<term> vec;

    
    for (int i = 0; i < 1; ++i)
        vec.push_back(term("aa",i));

class term {
public:
    string a;
    int b;
    term(const string& str, int c):a(str), b(c){}
    
};


sizeof(term)的大小是36

push_back第一个时,这时就从内存池里申请了20个40byte的块,一块返回作为vector的一个元素,另外19个串成单链表放入freelist[4]中

push_back第二个时,将40byte的块返还freelist,从内存池中申请20个72byte的块,一块返回作为vector的一个元素,另外19个串成单链表放入freelist[4]中

当元素较多时,就不再用freelist中的块,这时就是,用多少,就malloc多少内存,这时因为vector是连续地址的,所以要找一个连续的内存块


注意,erase,pop_back都不会减少vector所占内存。

当vector被析构时,先依存析构元素,最后再处理vector所占内存。如果这块内存比较小,小于等于128,则还是返还给freelist;如果内存块大于128,就直接释放这块内存


stl有一个比较好的思想,就是stl所有容器的内存分配都是用同一个freelist和内存池,这样就减少了内存碎片和频繁申请内存和释放内存的费时操作

但是这样会有一个副作用,就是程序在长时间的运行中,freelist所带的内存块可能会很多很多,就很占用系统资源,这些内存块又不能主动释放


sgi stl的二级配置器的工作原理是:

如果用户申请的内存>=128,调用第一级配置器,也就是malloc 和free


否则,用二级配置器。

二级配置器,有一个freelist和一个内存池。freelist是一个具有16个元素的数组,每个元素就是一条空闲块的链表,每条链表中的空闲块大小一致,而相邻链表中的空闲块大小相差2倍

如果用户free的内存块大小小于128,就插入到对应freelist的链表的表头

如果用户申请的内存块小于128,并且对应的链表有空闲块,就直接返回此内存块。如果此链表没有空闲块了,则就向内存池申请20个内存块,返回一个给用户,剩下的19个连接成对应的链表。但是,如果内存池空间不足,可能申请不到20个内存块,但内存池的剩余空间至少能供应一个块,同样返回。


如果,内存池空间一个块都不能供应了,那就通过malloc获取40个内存块大小的空间,将20个返回,剩下的空间留在内存池,供下次使用。


如果内存空间已经用尽,malloc也不能获取内存了,那么就要查看freelist中的空闲块,设用户申请的内存大小为p, 那么先查看大于p的最小块所在的链表是否为空,不为空,就将这个内存块放入内存池中,否则,就查看更大的块所在的链表




深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值