很多时候我们不要用默认的allocator的实现,我们需要自己的内存配置,所以我们可以做自己的分配器,这里说说必须要有的一些注意事项,因为有些是我犯错过的。
附上代码:
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特化的分配器。