一,基础篇
很多时候我们不要用默认的allocator的实现,我们需要自己的内存配置,所以我们可以做自己的分配器,这里说说必须要有的一些注意事项,因为有些是我犯错过的。
- 需要有自己的一些类型定义比如pointer
- 需要做自己的allocate和deallocate
- 一定要有rebind实现,如果不理解,请看一下标准库里面的list,set等的实现,很容易的。
附上代码:
- template <typename T>
- class MyAlloc : public allocator<T>
- {
- public:
- typedef size_t size_type;
- typedef typename allocator<T>::pointer pointer;
- typedef typename allocator<T>::value_type value_type;
- typedef typename allocator<T>::const_pointer const_pointer;
- typedef typename allocator<T>::reference reference;
- typedef typename allocator<T>::const_reference const_reference;
- template <typename U>
- struct rebind
- {
- typedef MyAlloc<U> other;
- };
- pointer allocate(size_type _Count, const void* _Hint = NULL)
- {
4. 做了rebind之后。一定要实现默认构造函数和非同类型一个模板的复制构造函数,最后的代码就如下了:
- class MaObjectDisplay1
- {
- private:
- string DisplayString;
- public:
- MaObjectDisplay1(const char *str)
- :DisplayString(str)
- {
- DisplayString += '\n';
- }
- void operator() (const int &inObj)
- {
- printf("inobj %d\n", inObj);
- }
- bool operator < (const MaObjectDisplay1 & in) const
- {
- return false;
- }
- };
- //this alloc class is just for the stl set<> allocator
- template <typename T>
- class MyAllc : public allocator<T>
- {
- public:
- typedef size_t size_type;
- typedef typename allocator<T>::pointer pointer;
- typedef typename allocator<T>::value_type value_type;
- typedef typename allocator<T>::const_pointer const_pointer;
- typedef typename allocator<T>::reference reference;
- typedef typename allocator<T>::const_reference const_reference;
- pointer allocate(size_type _Count, const void* _Hint = NULL)
- {
- void *rtn = NULL;
- //EthCFMMgntRbTreeMem::GetMemInstance()->malloc(_Count, rtn);
- return (pointer)rtn;
- }
- void deallocate(pointer _Ptr, size_type _Count)
- {
- //EthCFMMgntRbTreeMem::GetMemInstance()->free(_Ptr);
- }
- template<class _Other>
- struct rebind
- { // convert this type to allocator<_Other>
- typedef MyAllc<_Other> other;
- };
- MyAllc() throw()
- {}
- MyAllc(const MyAllc& __a) throw()
- : allocator<T>(__a)
- {}
- template<typename _Tp1>
- MyAllc(const MyAllc<_Tp1>&) throw()
- {}
- ~MyAllc() throw()
- {}
- };
- int main()
- {
- set<MaObjectDisplay1, less<MaObjectDisplay1 >, MyAllc<MaObjectDisplay1> > myset;
- MaObjectDisplay1 a("asdf");
- myset.insert(a);
- }
二、进阶篇 (一)
如果需要内存分配释放有不同的实现,那么,就需要把分配器扩展了,我们可以先试试使用模板参数来提供内存的分配和释放的核心,如下:
- #include <stdio.h>
- #include <set>
- using namespace std;
- class M1
- {
- public:
- static void *getMem(int size)
- {
- return malloc(size);
- }
- static void putMem(void *ptr)
- {
- return free(ptr);
- }
- };
- class M2
- {
- public:
- static void *getMem(int size)
- {
- return malloc(size);
- }
- static void putMem(void *ptr)
- {
- return free(ptr);
- }
- };
- //this alloc class is just for the stl set<> allocator
- template <typename T, typename M>
- class MyAllc : public allocator<T>
- {
- public:
- typedef size_t size_type;
- typedef typename allocator<T>::pointer pointer;
- typedef typename allocator<T>::value_type value_type;
- typedef typename allocator<T>::const_pointer const_pointer;
- typedef typename allocator<T>::reference reference;
- typedef typename allocator<T>::const_reference const_reference;
- pointer allocate(size_type _Count, const void* _Hint = NULL)
- {
- _Count *= sizeof(value_type);
- void *rtn = M::getMem(_Count);
- return (pointer)rtn;
- }
- void deallocate(pointer _Ptr, size_type _Count)
- {
- M::putMem(_Ptr);
- }
- template<class _Other>
- struct rebind
- { // convert this type to allocator<_Other>
- typedef MyAllc<_Other, M> other;
- };
- MyAllc() throw()
- {}
- /*MyAllc(const MyAllc& __a) throw()
- : allocator<T>(__a)
- {}*/
- template<typename _Tp1, typename M1>
- MyAllc(const MyAllc<_Tp1, M1>&) throw()
- {}
- ~MyAllc() throw()
- {}
- };
- int main()
- {
- set<int, less<int >, MyAllc<int, M1> > set1;
- set<int, less<int >, MyAllc<int, M2> > set2;
- set1.insert(1);
- set2.insert(2);
- set1.erase(1);
- set2.erase(2);
- }
这种情况,模板参数是多参了,所以要注意rebind的实现,保证第二个参数不要变,而且,标准库使用rebind的时候,都是单参的,所以我们要提供的依旧是单参的版本,比如看看标准库的使用:
- template<class _Ty,
- class _Alloc0>
- struct _Tree_base_types
- { // types needed for a container base
- typedef _Alloc0 _Alloc;
- typedef _Tree_base_types<_Ty, _Alloc> _Myt;
- #if _HAS_CPP0X
- typedef _Wrap_alloc<_Alloc> _Alty0;
- typedef typename _Alty0::template rebind<_Ty>::other _Alty;
- #else /* _HAS_CPP0X */
- typedef typename _Alloc::template rebind<_Ty>::other _Alty;
- #endif /* _HAS_CPP0X */
- typedef typename _Get_voidptr<_Alty, typename _Alty::pointer>::type
- _Voidptr;
- typedef _Tree_node<typename _Alty::value_type,
- _Voidptr> _Node;
- typedef typename _Alty::template rebind<_Node>::other _Alnod_type;
三、进阶篇 (二)
对于模板多参数,可能有些人不能接受,所以,还有一种办法,对于特定的对象分配,使用不同的allocate版本,就可以对模板类成员函数做一个特化。
- class M1
- {
- public:
- static void *getMem(int size)
- {
- return malloc(size);
- }
- static void putMem(void *ptr)
- {
- return free(ptr);
- }
- };
- class M2
- {
- public:
- static void *getMem(int size)
- {
- return malloc(size);
- }
- static void putMem(void *ptr)
- {
- return free(ptr);
- }
- };
- //this alloc class is just for the stl set<> allocator
- template <typename T>
- class MyAllc : public allocator<T>
- {
- public:
- typedef size_t size_type;
- typedef typename allocator<T>::pointer pointer;
- typedef typename allocator<T>::value_type value_type;
- typedef typename allocator<T>::const_pointer const_pointer;
- typedef typename allocator<T>::reference reference;
- typedef typename allocator<T>::const_reference const_reference;
- pointer allocate(size_type _Count, const void* _Hint = NULL)
- {
- _Count *= sizeof(value_type);
- void *rtn = M1::getMem(_Count);
- return (pointer)rtn;
- }
- void deallocate(pointer _Ptr, size_type _Count)
- {
- M1::putMem(_Ptr);
- }
- template<class _Other>
- struct rebind
- { // convert this type to allocator<_Other>
- typedef MyAllc<_Other> other;
- };
- MyAllc() throw()
- {}
- /*MyAllc(const MyAllc& __a) throw()
- : allocator<T>(__a)
- {}*/
- template<typename _Tp1>
- MyAllc(const MyAllc<_Tp1>&) throw()
- {}
- ~MyAllc() throw()
- {}
- };
- template<>
- MyAllc<double>::pointer MyAllc<double>::allocate(size_type _Count, const void* _Hint)
- {
- _Count *= sizeof(value_type);
- void *rtn = M2::getMem(_Count);
- return (pointer)rtn;
- }
- template<>
- void MyAllc<double>::deallocate(pointer _Ptr, size_type _Count)
- {
- M2::putMem(_Ptr);
- }
- int main()
- {
- MyAllc<double> aAllc;
- aAllc.allocate(1);
- aAllc.deallocate(NULL, 1);
- set<int, less<int >, MyAllc<int> > set1;
- set<double, less<double >, MyAllc<double> > set2;
- int a = 1;
- double b = 2;
- set1.insert(a);
- set2.insert(b);
- set1.erase(a);
- set2.erase(b);
- }
对于MyAllc<double> aAllc进行的allocate操作,都是使用的特化的,但是后面的set2.insert(b);,根本不会使用特化的内存分配器,为什么呢?呵呵,这个很简单了,set分配内存的单位不是double,而是RBTree_node<double>,所以不适用double特化的分配器。