最简单的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 memorystatic 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的返回值就是pvoid (* 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());}elseinsert(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;}elseinsert_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的最小块所在的链表是否为空,不为空,就将这个内存块放入内存池中,否则,就查看更大的块所在的链表

sgi 之vector相关推荐

  1. sgi---1 vector

    sgi的vector在实现时采用了内存池和freelist的数据结构,大大加快了vector添加新元素的速度. 但是有一个问题在于,内存池不能回收已经分配的内存. http://blog.csdn.n ...

  2. SGI STL 学习笔记二 vector

    sequence containers Array Vector Heap Priority_queue List sList(not in standard) Deque Stack Queue S ...

  3. c++ vector 先进先出_C++ STL Vector(容器)学习

    本文参考博客链接及书籍: 侯捷老师的<STL 源码剖析> 在C++标准库中,STL容器是一些常用数据结构的实现,比如数组.链表.树.栈.队列.散列表.集合.映射表等,可以分为序列式(seq ...

  4. STL的Vector, List and Deque

    stl提供了三个最基本的容器:vector,list,deque. vector和built-in数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此 它能非常好的支持随即存取,即[]操作符,但 ...

  5. sgi allocate

    这几天在研究stl的内存配置器,作用是防止零散的申请内存块导致过多的内存碎片. 大体思路是: 维护一个freelist, 一个内存块链表,就是一个链表,链表上的每一个节点都一个指针指向一块内存块,如果 ...

  6. STL源码剖析---vector

    vector容器概述       vector的数据安排以及操作方式,与array非常相似.两者的唯一区别在于空间的运用的灵活性.array是静态空间,一旦配置了就不能改变:要换个大(或小)一点的房子 ...

  7. 栈与队列在SGI STL的底层实现

    栈 栈提供push和pop等接口,不提供走访功能,也不提供迭代器. STL中栈不被归类为容器,而被归类为container adapter(容器适配器),这是因为栈是以底层容器完成其所有的工作,对外提 ...

  8. STL源码剖析 序列式容器|Vector

    容器的概观和分类 array 数组 .list 链表.tree树 .stack堆栈.queue队列.hash table散列表.set集合.map映射表 根据数据在容器中的排列顺序,将上述数据结构分为 ...

  9. STL中map和string, vector 用法详解

    1. map 用法详解 std map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成 ...

最新文章

  1. java序列化库_java 中序列化(Serializable)
  2. 2021-03-31 Matlab simulink 模糊PID在无刷直流电机中的应用
  3. 学计算机选电脑,大学准备学计算机,选怎样配置的电脑好?
  4. 复制模式和扩展模式_扩展剂:模式还是反模式?
  5. 常用JavaScript函数 31 - 46(自我总结)
  6. 关于产品与数据该如何结合的一点想法(一)
  7. Ghost for linux 工具备份还原系统
  8. android自动完成输入框,Android——自动完成输入框提示功能的菜单_AutoCompleteTextView...
  9. MySQL 入门(十一)—— 运算符
  10. 第一章课后习题源代码(笔记自用)
  11. excel的IRR函数中的预估值有什么用
  12. 注册表编辑器,任务管理器,己被系统管理员停用----应急响应
  13. 群晖docker搭建halo个人博客
  14. jpress-项目升级
  15. 微信公众号编辑器图片上传后有白色背景
  16. win10 的 PS 不能直接拖进文件的解决方法(附:与 Edge 登录的冲突)
  17. Linux 设备模型基本概念 (一)
  18. mysql 加盐_【mysql】当加盐算法需要改变,数据库该如何更新?
  19. IB 物理真题: 比潜热、理想气体
  20. OpenCV——LCC(Local Color Correction)的Python复现

热门文章

  1. Android 蓝牙4.0(BLE)开发实现对蓝牙的写入数据和读取数据
  2. 四十五、和我一起看看,国外的Python考试到底是怎么样(上篇)
  3. 下一代对话系统中的关键技术(上篇)
  4. 直播 | 腾讯天衍实验室张子恒:详细解读天衍实验室知识图谱对齐技术
  5. 2.5万美元奖金!滴滴算法工程师详解专业赛事:2021 SIGSPATIAL GISCUP
  6. 如何理解 Graph Convolutional Network (GCN)?
  7. 预告 | AIS (ACL, IJCAI, SIGIR) 2019 论文报告会日程安排
  8. 【归并排序】求逆序数算法
  9. 西安电子科技大学第16届程序设计竞赛 E题
  10. c++ createtoolhelp32snapshot取进程路径_Linux进程间通信(上)之管道、消息队列实践