STL 之 空间适配器

1.sgi
STL"标准"的空间适配器:

该适配器很简单,只是对new delete等内存分配释放函数的一层简单封装而已,所以sgi
stl几乎没用上它(效率太低),代码位于defalloc.h.

2.sgi stl特殊适配器
std::alloc:

该版本作为stl中的默认适配器,主要分成两个部分:

#include
<stl_alloc.h>         
//空间配置与释放

#include
<stl_construct.h>   //空间内对象的构造与析构

2.1.对象构造与析构:


 1 template <class T>
2 inline void destroy(T* pointer) {
3 pointer->~T();
4 }
5
6 template <class T1, class T2>
7 inline void construct(T1* p, const T2& value) {
8 new (p) T1(value);
9 }
10
11 template <class ForwardIterator>
12 inline void
13 __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
14 for ( ; first < last; ++first)
15 destroy(&*first);
16 }
17
18 template <class ForwardIterator>
19 inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}
20
21 template <class ForwardIterator, class T>
22 inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
23 typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
24 __destroy_aux(first, last, trivial_destructor());
25 }
26
27 template <class ForwardIterator>
28 inline void destroy(ForwardIterator first, ForwardIterator last) {
29 __destroy(first, last, value_type(first));
30 }
31
32 inline void destroy(char*, char*) {}
33 inline void destroy(wchar_t*, wchar_t*) {}

2.2.空间配置与释放:

sgi中该部分有两个版本:

一级配置器:负责申请/释放的内存空间比较大时直接调用malloc /
free完成。

二级配置器:解决当申请/释放的空间比较小的的内存碎片问题,用内存池完成。

2.2.1.一级配置器:


 1 template <int inst>
2 class __malloc_alloc_template {
3
4 private:
5
6 static void *oom_malloc(size_t);
7
8 static void *oom_realloc(void *, size_t);
9
10 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
11 static void (* __malloc_alloc_oom_handler)();
12 #endif
13
14 public:
15
16 static void * allocate(size_t n)
17 {
18 void *result = malloc(n);
19 if (0 == result) result = oom_malloc(n);
20 return result;
21 }
22
23 static void deallocate(void *p, size_t /* n */)
24 {
25 free(p);
26 }
27
28 static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
29 {
30 void * result = realloc(p, new_sz);
31 if (0 == result) result = oom_realloc(p, new_sz);
32 return result;
33 }
34
35 static void (* set_malloc_handler(void (*f)()))()
36 {
37 void (* old)() = __malloc_alloc_oom_handler;
38 __malloc_alloc_oom_handler = f;
39 return(old);
40 }
41
42 };
43
44 // malloc_alloc out-of-memory handling
45
46 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
47 template <int inst>
48 void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
49 #endif
50
51 template <int inst>
52 void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
53 {
54 void (* my_malloc_handler)();
55 void *result;
56
57 for (;;) {
58 my_malloc_handler = __malloc_alloc_oom_handler;
59 if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
60 (*my_malloc_handler)();
61 result = malloc(n);
62 if (result) return(result);
63 }
64 }
65
66 template <int inst>
67 void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
68 {
69 void (* my_malloc_handler)();
70 void *result;
71
72 for (;;) {
73 my_malloc_handler = __malloc_alloc_oom_handler;
74 if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
75 (*my_malloc_handler)();
76 result = realloc(p, n);
77 if (result) return(result);
78 }
79 }
80
81 typedef __malloc_alloc_template<0> malloc_alloc;

注:typedef
__malloc_alloc_template<0>
malloc_alloc;
      typedef
malloc_alloc alloc;

2.2.2.二级配置器:


  1 template <bool threads, int inst>
2 class __default_alloc_template
3 {
4
5 private:
6
7 # ifndef __SUNPRO_CC
8 enum {__ALIGN = 8};
9 enum {__MAX_BYTES = 128};
10 enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
11 # endif
12
13 static size_t ROUND_UP(size_t bytes) {
14 return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
15 }
16
17 __PRIVATE:
18 union obj {
19 union obj * free_list_link;
20 char client_data[1]; /* The client sees this.*/
21 };
22
23 private:
24 static obj * __VOLATILE free_list[__NFREELISTS];
25
26 static size_t FREELIST_INDEX(size_t bytes) {
27 return (((bytes) + __ALIGN-1)/__ALIGN - 1);
28 }
29
30 // Returns an object of size n, and optionally adds to size n free list.
31 static void *refill(size_t n);
32
33 // Allocates a chunk for nobjs of size "size". nobjs may be reduced
34 // if it is inconvenient to allocate the requested number.
35 static char *chunk_alloc(size_t size, int &nobjs);
36
37 // Chunk allocation state.
38 static char *start_free;
39 static char *end_free;
40 static size_t heap_size;
41
42
43
44 public:
45 __default_alloc_template()
46 {
47 if (!__node_allocator_lock_initialized) {
48 InitializeCriticalSection(&__node_allocator_lock);
49 __node_allocator_lock_initialized = true;
50 }
51 }
52
53
54
55 static void * allocate(size_t n)
56 {
57 obj * __VOLATILE * my_free_list;
58 obj * __RESTRICT result;
59
60 if (n > (size_t) __MAX_BYTES) {
61 return(malloc_alloc::allocate(n));
62 }
63 my_free_list = free_list + FREELIST_INDEX(n);
64 result = *my_free_list;
65 if (result == 0) {
66 void *r = refill(ROUND_UP(n));
67 return r;
68 }
69 *my_free_list = result -> free_list_link;
70 return (result);
71 };
72
73
74
75 static void deallocate(void *p, size_t n)
76 {
77 obj *q = (obj *)p;
78 obj * __VOLATILE * my_free_list;
79
80 if (n > (size_t) __MAX_BYTES) {
81 malloc_alloc::deallocate(p, n);
82 return;
83 }
84 my_free_list = free_list + FREELIST_INDEX(n);
85 q -> free_list_link = *my_free_list;
86 *my_free_list = q;
87 }
88
89
90 static void * reallocate(void *p, size_t old_sz, size_t new_sz);
91 } ;
92
93
94
95
96 //注:
97 typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
98 typedef __default_alloc_template<false, 0> single_client_alloc;
99
100
101
102
103 /* We allocate memory in large chunks in order to avoid fragmenting */
104 /* the malloc heap too much. */
105 /* We assume that size is properly aligned. */
106 /* We hold the allocation lock. */
107 template <bool threads, int inst>
108 char*
109 __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
110 {
111 char * result;
112 size_t total_bytes = size * nobjs;
113 size_t bytes_left = end_free - start_free;
114
115 if (bytes_left >= total_bytes) {
116 result = start_free;
117 start_free += total_bytes;
118 return(result);
119 } else if (bytes_left >= size) {
120 nobjs = bytes_left/size;
121 total_bytes = size * nobjs;
122 result = start_free;
123 start_free += total_bytes;
124 return(result);
125 } else {
126 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
127 // Try to make use of the left-over piece.
128 if (bytes_left > 0) {
129 obj * __VOLATILE * my_free_list =
130 free_list + FREELIST_INDEX(bytes_left);
131
132 ((obj *)start_free) -> free_list_link = *my_free_list;
133 *my_free_list = (obj *)start_free;
134 }
135 start_free = (char *)malloc(bytes_to_get);
136 if (0 == start_free) {
137 int i;
138 obj * __VOLATILE * my_free_list, *p;
139 // Try to make do with what we have. That can‘t
140 // hurt. We do not try smaller requests, since that tends
141 // to result in disaster on multi-process machines.
142 for (i = size; i <= __MAX_BYTES; i += __ALIGN) {
143 my_free_list = free_list + FREELIST_INDEX(i);
144 p = *my_free_list;
145 if (0 != p) {
146 *my_free_list = p -> free_list_link;
147 start_free = (char *)p;
148 end_free = start_free + i;
149 return(chunk_alloc(size, nobjs));
150 // Any leftover piece will eventually make it to the
151 // right free list.
152 }
153 }
154 end_free = 0; // In case of exception.
155 start_free = (char *)malloc_alloc::allocate(bytes_to_get);
156 // This should either throw an
157 // exception or remedy the situation. Thus we assume it
158 // succeeded.
159 }
160 heap_size += bytes_to_get;
161 end_free = start_free + bytes_to_get;
162 return(chunk_alloc(size, nobjs));
163 }
164 }
165
166
167 /* Returns an object of size n, and optionally adds to size n free list.*/
168 /* We assume that n is properly aligned. */
169 /* We hold the allocation lock. */
170 template <bool threads, int inst>
171 void* __default_alloc_template<threads, inst>::refill(size_t n)
172 {
173 int nobjs = 20;
174 char * chunk = chunk_alloc(n, nobjs);
175 obj * __VOLATILE * my_free_list;
176 obj * result;
177 obj * current_obj, * next_obj;
178 int i;
179
180 if (1 == nobjs) return(chunk);
181 my_free_list = free_list + FREELIST_INDEX(n);
182
183 /* Build free list in chunk */
184 result = (obj *)chunk;
185 *my_free_list = next_obj = (obj *)(chunk + n);
186 for (i = 1; ; i++) {
187 current_obj = next_obj;
188 next_obj = (obj *)((char *)next_obj + n);
189 if (nobjs - 1 == i) {
190 current_obj -> free_list_link = 0;
191 break;
192 } else {
193 current_obj -> free_list_link = next_obj;
194 }
195 }
196 return(result);
197 }
198
199 template <bool threads, int inst>
200 void*
201 __default_alloc_template<threads, inst>::reallocate(void *p,
202 size_t old_sz,
203 size_t new_sz)
204 {
205 void * result;
206 size_t copy_sz;
207
208 if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES) {
209 return(realloc(p, new_sz));
210 }
211 if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p);
212 result = allocate(new_sz);
213 copy_sz = new_sz > old_sz? old_sz : new_sz;
214 memcpy(result, p, copy_sz);
215 deallocate(p, old_sz);
216 return(result);
217 }
218
219
220
221
222 template <bool threads, int inst>
223 char *__default_alloc_template<threads, inst>::start_free = 0;
224
225 template <bool threads, int inst>
226 char *__default_alloc_template<threads, inst>::end_free = 0;
227
228 template <bool threads, int inst>
229 size_t __default_alloc_template<threads, inst>::heap_size = 0;
230
231 template <bool threads, int inst>
232 __default_alloc_template<threads, inst>::obj * __VOLATILE
233 __default_alloc_template<threads, inst> ::free_list[__default_alloc_template<threads, inst>::__NFREELISTS] =
234 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

注:typedef
__default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;

2.2.3.配置器接口层:

    


 1 template<class T, class Alloc>
2 class simple_alloc
3 {
4 public:
5 static T *allocate(size_t n)
6 { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
7 static T *allocate(void)
8 { return (T*) Alloc::allocate(sizeof (T)); }
9 static void deallocate(T *p, size_t n)
10 { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
11 static void deallocate(T *p)
12 { Alloc::deallocate(p, sizeof (T)); }
13 };

    

    接口用法示例:

    


 1 template <class T, class Alloc = alloc>
2 class vector
3 {
4 public:
5 typedef T value_type;
6 typedef value_type* pointer;
7 typedef const value_type* const_pointer;
8 typedef value_type* iterator;
9 typedef const value_type* const_iterator;
10 typedef value_type& reference;
11 typedef const value_type& const_reference;
12 typedef size_t size_type;
13 typedef ptrdiff_t difference_type;
14
15 //....................
16
17 protected:
18 typedef simple_alloc<value_type, Alloc> data_allocator;
19 }

    

STL 之 空间适配器,布布扣,bubuko.com

时间: 2024-10-05 23:53:08

STL 之 空间适配器的相关文章

C++标准库——STL之空间配置器

声明:源码同<STL源码剖析>(侯捷) STL: C++标准的模板库,通用性高. 常见的数据结构封装. 提供常用的通用算法. STL六大组件: 容器      算法       迭代器       仿函数(函数对象)     适配器      配置器 空间配置器的作用: 1.提高代码复用率,功能模块化. 2.减少内存碎片问题. 比如我们list是链式结构,如果其中的成员是一个个new出来的,我们知道new的底层实现是malloc,同时也必须清楚,当malloc一块40字节空间时,操作系统为了能

stl仿函数和适配器

所谓的适配器就是底层利用仿函数,然后修改仿函数的接口,达到自己的目的: 例如:template<class operation> class binder1st的适配器,其本质是一个类,它的模板参数operation其实是仿函数类(仿函数其实是struct类),内部函数调用operator()(const typename Operation::second_argument_type& x) const,其中x是我们适配器调用的参数,由于此适配器的目的就是绑定第一个参数,使得我们的调

STL之stack适配器的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 一提到适配器(adapter),我们就想到了早期用电话线上网所用的调制解调器,俗称"猫","猫"的作用是实现数模转化和模数转化,在客户端,它可以将电话的模拟信息转化为我们计算机能够接收的数字信息,所以猫相当于一个转换器.再举个更加好理解的例子来说明"适配器"的含义.相信在我们每个人的家里都有插排,假设就这么一种情况,现在我们家里的墙壁上只有一个三角的插口,而我们的电视却是两个口,怎么办?毫无疑问

STL之容器适配器priority_queue的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 在前面的文章STL之heap相关操作算法中介绍了堆的相关操作算法,由于堆的注意主要作用是用于排序,我们也知道堆排序的时间复杂度为o(nlogn),是一种不稳定的排序算法,利用堆这一数据结构,我们可以很快第获取一个大数据中最大(或最小)的k个数.同时,上篇文章中,也提出了相关heap算法的一些问题. 问题1:在调用push_heap函数实现向堆中插入元素之前,我们必须要先将向底层容器的末端插入该元素,然后才能调用push_heap内部的向上调整来

STL之容器适配器queue的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 上篇文章STL之容器适配器stack的实现框架已经介绍了STL是如何借助基础容器实现一种常用的数据结构stack (栈),本文介绍下另外一种STL内部定义的另外一种STL容器适配器queue(队列). 对于接触过数据结构的人来说,队列并不陌生,它是一种FIFO(first in first out)的数据结构.与栈相比,队列的不同之处在于:(1)队列是一种先进先出的数据结构,而栈则是一种后进先出的数据结构:(2)队列支持首尾两端的访问操作,而栈

初探STL之容器适配器

容器适配器 特点 用某种顺序容器来实现(让已有的顺序容器以栈/队列的方式工作) 分类 1) stack: 头文件 <stack> ? 栈 -- 后进先出 2) queue: 头文件 <queue> ? 队列 -- 先进先出 3) priority_queue: 头文件 <queue> ? 优先级队列 -- 最高优先级元素总是第一个出列 注: 容器适配器上没有迭代器 STL中各种排序, 查找, 变序等算法都不适合容器适配器 Stack 特点 1.stack 是后进先出的数

STL容器及适配器

STL容器   1.序列式容器 : vector,deque,list. 每个元素都有固定的位置(取决于插入的时机和位置,与元素值无关). vector 特点: 将一个元素置于一个动态数组中加以管理,可以随机存取元素.在数组尾部添加或删除元素非常快速,但是在中部或头部插入或删除元素比较耗时. deque "double-ended queue" 双端队列,可以随机存取.数组尾部或头部添加或删除元素非常快速,但在中部插入或删除元素比较费时.实际上,deque 是对vector 和list

STL之容器适配器stack的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 一提到适配器(adapter).我们就想到了早期用电话线上网所用的调制解调器,俗称"猫"."猫"的作用是实现数模转化和模数转化,在client,它能够将电话的模拟信息转化为我们计算机能够接收的数字信息,所以猫相当于一个转换器.再举个更加好理解的样例来说明"适配器"的含义.相信在我们每一个人的家里都有插排,如果就这么一种情况.如今我们家里的墙壁上仅仅有一个三角的插口,而我们的电视却是两个口,怎么办

STL 之 空间配置器(allocator)

一.SGI 标准的空间配置器,std::allocator SGI也定义了一个符合部分标准,名为allocator的配置器,但是它自己不使用,也不建议我们使用,主要原因是效率不佳. 它只是把C++的操作符::operator new和::operator delete做了一层简单的封装而已. 二.SGI 特殊的空间配置器,std::alloc 由于SGI 标准的空间配置器只是把C++的操作符::operator new和::operator delete做了一层简单的封装,没有考虑到任何效率上的