LightSTL:(2)最简版 内存分配器的设计

内存分配器 Allocator 是为容器元素配置内存空间的类,从使用者的角度来说,Allocator一般隐藏在幕后,且无特殊需要,不会关注它。
然而,Allocator是容器创建的基石,是自己实现STL容器必不可少的第一步,同时,Allocator的设计会影响容器使用的效率。
在这里,为了尽快进入STL更加激动人心的实现部分,先仅仅实现了一个最简版本的 default allocator,后续可以在该版本之上再针对Allocator进行优化和扩充。

STL定义的Allocator的接口

STL对Allocator进行了规定,给出了Allocator的allocator 标准接口,可以参见cplusplus网站的说明。在这里,列出如下:

1.模板定义

template
class allocator;

2. 类型定义

memberdefinitioncomment
value_typeT元素类型
pointerT*元素指针
referenceT&引用
const_pointerconst T*常量指针
const_referenceconst T&常量引用
size_typesize_t元素数量
difference_typeptrdiff_t两个指针之间的距离
rebindmember classIts member type other is the equivalent allocator type to allocate elements of type Type

3. 成员函数

member functioncomment
(constructor)可选的构造函数
(destructor)可选的析构函数
allocate分配内存
deallocate释放内存
constructnew相应的对象
destroydelete相应的对象
address返回对象地址,还有const版本
max_size返回可成功配置的最大量

allocator模板类的实现

1.类型定义

STL定义的接口中,difference_type、reference等名称看起来有些怪怪的,针对一个分配器为何要定义这么复杂的类型?事实上,这些内容和后续的迭代器设计及traits编程技法是相关的,这里定义这些是为了和迭代器等类保持一致。这些变量的定义直接用typedef关键字即可。

	template <class T>
	class allocator
	{
	public:
		typedef T		   value_type;
		typedef T*         pointer;
		typedef const T*   const_pointer;
		typedef T&         reference;
		typedef const T&   const_reference;
		typedef size_t     size_type;
		typedef ptrdiff_t  difference_type;

		//rebind allocator of type U.   
		template <class U>
		struct rebind
		{  typedef allocator<U> other; };
		
		//... funcs
	}

2. 成员函数定义

在规定的成员函数中,最重要的四个接口是allocate()deallocate()construct()destory(),其中前两个负责空间的分配与释放,后两个负责对象的构造与析构。为何要将空间操作和对象操作分开呢?
事实上,我们比较习惯的C++内存分配方式是基于newdelete,如下方式,newdelete都包含空间和对象的操作。

class A
{	.... /*data and funcs*/  };
A* obj = new A();   //new中包含 空间配置 和 对象构造
delete A;           //delete中包含对象析构和空间释放

但是对于泛化的情况来说,空间操作和对象操作一起操作在某些情况下可能效率很低,因此出于效率的考虑,将这两部分独立开来设计。
虽然有这样的考虑,但是在这里为了设计最简单的分配器,在具体实现上并没有考虑太多,仅仅对newdelete进行了简单的包装,可能效率还更低一点,但是在这样的架构下,优化的潜力是不可估量的。
为了程序的复用性,在这里,首先给出了函数模板形式的_allocate()_deallocate()_construct()_destory()
其中,_construct()利用C++的 placement new 运算子将初值设定到指针所指的空间上。

	template <class T>
	inline T* _allocate(ptrdiff_t size, T*)
	{
		std::set_new_handler(0);
		T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
		if (tmp == 0)
		{
			std::cerr << "out of memeory" << std::endl;
			exit(1);
		}
		return tmp;
	}

	template <class T>
	inline void _deallocate(T* buffer)
	{ ::operator delete(buffer);}

	template <class T1, class T2>
	inline void _construct(T1* p, const T2& value)
	{ new(p) T1(value); } // placement new.invoke constructor of T1

	template <class T>
	inline void _destory(T* ptr)
	{ ptr->~T(); }

然后在allocator中对它们进行了调用,在这里,allocator作为一个工具类,其函数要定义为静态的,方便以allocator<T>::的形式调用。

	template <class T>
	class allocator
	{
	public:
		//...
		static pointer allocate(size_type n, const void* hint=0)
		{ return _allocate((difference_type)n, (pointer)0); }

		static void deallocate(pointer p)
		{ _deallocate(p); }

		static void construct(pointer p, const T& value)
		{ _construct(p, value); }

		static void destory(pointer p)
		{ _destory(p); }
	}

allocator除了上面的几个函数,还有address()max_size(),给出如下:

		static pointer address(reference x)
		{ return (pointer)&x; }

		static const_pointer const_address(const_reference x)
		{ return (const_pointer)&x; }

		static size_type max_size()
		{ return size_type(UINT_MAX / sizeof(T)); }

全部代码 Allocator.h

下面给出全部的代码

#ifndef ALLOCATOR_H
#define ALLOCATOR_H

#include <new>      //for placement new
#include <cstddef>  //for ptrdiff_t, size_t
#include <cstdlib>  //for exit()
#include <climits>  //for UNIT_MAX
#include <iostream> //for cerr

namespace LightSTL
{
	template <class T>
	inline T* _allocate(ptrdiff_t size, T*)
	{
		std::set_new_handler(0);
		T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
		if (tmp == 0)
		{
			std::cerr << "out of memeory" << std::endl;
			exit(1);
		}
		return tmp;
	}

	template <class T>
	inline void _deallocate(T* buffer)
	{ ::operator delete(buffer);}

	template <class T1, class T2>
	inline void _construct(T1* p, const T2& value)
	{ new(p) T1(value); } // placement new.invoke ctor of T1

	template <class T>
	inline void _destory(T* ptr)
	{ ptr->~T(); }

	template <class T>
	class allocator
	{
	public:
		typedef T		   value_type;
		typedef T*         pointer;
		typedef const T*   const_pointer;
		typedef T&         reference;
		typedef const T&   const_reference;
		typedef size_t     size_type;
		typedef ptrdiff_t  difference_type;

		//rebind allocator of type U.   
		template <class U>
		struct rebind
		{  typedef allocator<U> other; };

		//hint used for locality.
		static pointer allocate(size_type n, const void* hint=0)
		{ return _allocate((difference_type)n, (pointer)0); }

		static void deallocate(pointer p)
		{ _deallocate(p); }

		static void construct(pointer p, const T& value)
		{ _construct(p, value); }

		static void destory(pointer p)
		{ _destory(p); }

		static pointer address(reference x)
		{ return (pointer)&x; }

		static const_pointer const_address(const_reference x)
		{ return (const_pointer)&x; }

		static size_type init_page_size()
		{ return max(size_type(1), size_type(4096 / sizeof(T))); }

		static size_type max_size()
		{ return size_type(UINT_MAX / sizeof(T)); }
	};

}//end of namespace

#endif // !ALLOCATOR_H

Test case:

	int* ia = LightSTL::allocator<int>::allocate(1);
	LightSTL::allocator<int>::construct(ia, 5);
	std::cout << *ia << std::endl;

	std::string* istr = LightSTL::allocator<std::string>::allocate(1);
	LightSTL::allocator<std::string>::construct(istr, "abcd");
	std::cout << *istr << std::endl;
	//output 
	//5
	//abcd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值