stl2




事实上SGI STL仍然提供了一个标准的配置器接口,只是把它做了一层隐藏。这个标准接口的配置器名为simple_alloc。


SGI STL的配置器与众不同,也与标准规范不同,其名称是alloc而非allocator,而且不接受任何参数。换句话说,如果你要在程序中明白采用SGI配置器,则不能采用标准写法:
vector<int, std::allocator<int> > iv;
必须这么写:
vector<int, std::alloc> iv;


SGI STL的每个容器都已经指定其缺省的空间配置器为alloc。例如下面的vector声明:
template<class T, class Alloc = alloc>
class vector{...};


虽然SGI也定义有一个符合部分标准、名为allocator的配置器,但SGI自己从未用过它,也不建议我们使用,在defalloc.h中。


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


STL标准规格告诉我们,配置器定义于<memory>之中,SGI <memory>内含以下两个文件:
#include <stl_alloc.h>
#include <stl_construct.h>


STL还规定配置器必须拥有名为constuct()和destroy()的两个成员函数,然而真正在SGI STL中大显身手的个名为std::alloc的配置器并未遵守这一规则。


下面是<stl_construct.h>的部分内容:
#include <new.h>
template<class T1, class T2>
inline void construct(T1 * p, const T2& value)
{
	new(p) T1(value);
}
template<class T>
inline void destroy(T * pointer)
{
	pointer->~T();
}
template<class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last)
{
	__destroy(first, last, value_type(first));
}
template<class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
	typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
	__destroy_aux(first, last, trivial_destructor());
}
template<class ForwardIterator>
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
	for(; first < last; ++first)
		destroy(&*first);
}
template<class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type){}
inline void destroy(char *, char *){}
inline void destroy(wchar_t *, wchar_t *){}
...........


stl_iterator相关文件里有以下内容:


template<class Iterator>
inline typename iterator_traits<Iterator>::value_type* value_type(const Iterator&)
{
	return static_cast<typename iterator_traits<Iterator>::value_type *>(0);
}


template<class Iterator>
struct iterator_traits
{
	typedef typename Iterator::iterator_category 	iterator_category;
	typedef typename Iterator::value_type 			value_type;
	typedef typename Iterator::defference_type		difference_type;
	typedef typename Iterator::pointer				pointer;
	typedef typename Iterator::reference			reference;
};
template<class T>
struct iterator_traits<T*>
{
	typedef random_access_iterator_tag 	iterator_category;
	typedef T 			value_type;
	typedef ptrdiff_t 	difference_type;
	typedef T* 			pointer;
	typedef T& 			reference;
};
template<class T>
struct iterator_traits<const T*>
{
	typedef random_access_iterator_tag 	iterator_category;
	typedef T 			value_type;
	typedef ptrdiff_t 	difference_type;
	typedef const T* 	pointer;
	typedef const T& 	reference;		
};


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;
};
然后接着是各种基本数据类型的特化版本。


整个设计究竟只开放第一级配置器,或是同时开放第二级配置器,取决于__USE_MALLOC是否被定义。


以下模板参数0没有派上用场
typedef __malloc_alloc_template<0> malloc_alloc
#ifdef __USE_MALLOC
typedef malloc_alloc alloc
#else
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc
#endif /* !__USE_MALLOC*/




第一级配置器:
#if 0
# 	include <new>
# 	define __THROW_BAD_ALLOC throw bad_alloc
#elif !define(__THROW_BAD_ALLOC)
# 	include <iostream>
# 	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 /*old_sz*/, size_t new_sz)
	{
		void * result = realloc(p, new_sz);
		if(0 == result)
			result = oom_realloc(p, new_sz);
		return result;
	}
	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 (*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);
	}
}


请注意,SGI第一级配置器allocate()和reallocate()都是在调用malloc()和realloc()不成功后,改调用oom_malloc()和oom_realloc()。后两者都有内循环,不断调用“内存不足处理例程”,期望在某次调用之后,获得足够的内存而圆满完成任务。但如果“内存不足处理例程”并未被客端设定,oom_malloc()和oom_realloc()便老实不客气地调用__THROW_BAD_ALLOC,丢出bad_alloc异常信息,或利用exit(1)硬生生中止程序。
记住,设计“内存不足处理例程”是客端的责任,设定“内存不足处理例程”也是客端的责任。再一次提醒你,“内存不足处理例程”解决问题的做法有着特定的模式。




enum {__ALIGN = 8};
enum {__MAX_BYTES = 128};
enum {__NFREELISTS = __MAX_BYTES / __ALIGN};
template<bool threads, int inst>
class __default_alloc_template
{
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);
	}
	//返回一个大小为n的对象,并可能加入大小为n的其它区块到free_list
	static void * refill(size_t n);
	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);
	static void deallocate(void * p, size_t n);
	static void * reallocate(void * p, size_t old_sz, size_t new_sz);
};
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>
__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 > (size_t)__MAX_BYTES)
	{
		return(malloc_alloc::allocate(n));
	}
	my_free_list = free_list + FREELIST_INDEX(n);
	result = *my_free_list;
	if(0 == result)
	{
		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>::deallocate(void * p, size_t n)
{
	obj * q = (obj *)p;
	obj * volatile * my_free_list;
	if(n > (size_t)__MAX_BYTES)
	{
		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;
}


//假设n已经适当上调至8的倍数
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);
	*my_free_list = next_obj = (obj *)(chunk + n);
	result = (obj *)chunk;
	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);
		}
		end_free = start_free + bytes_to_get;
		heap_size += bytes_to_get;
		return chunk_alloc(size, nobjs);
	}
}


template<class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result);
template<class ForwardIterator, class T>
void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x);
template<class ForwardIterator, class Size, class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
POD型别必然拥有trivial ctor/dtor/copy/assignment函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值