如何获得std::map的真正分配器

How to get the true allocator for the std::map?

本文关键字:分配器 map 何获得 std      更新时间:2023-10-16

我想打印STL映射容器的自定义内存分配器的工作结果。我想打印内存分配图
我的get_allocator()有问题。请参见示例
get_allocator()调用为初始pair<int,int>提供分配器。它甚至创造了它…

有没有一种方法可以获得真正的分配器(RBtreePool实例),它为映射的元素提供内存?

我正在使用gcc。谢谢

#include <memory>
#include <map>
using namespace std;
class Pool {
  //...
public:
  Pool(unsigned n);
  ~Pool();
  void* alloc();  
  void free(void*);
  void print_mm();  //print pool map
  //...
};
void* Pool::alloc() {
  //...
}
//...
void Pool::print_mm() {
  //...
}
template<class T> class Pool_alloc : public allocator<T> {
  static Pool pool;
public:
  template<class U> struct rebind {
    typedef Pool_alloc<U> other;
  };
  template<class U> Pool_alloc(const Pool_alloc<U>&) {}
  Pool_alloc() {}
  T* allocate(size_t, void*);
  void deallocate(T*, size_t);
  void print_mm() {pool.print_mm();}
};
template<class T> Pool Pool_alloc<T>::pool(sizeof(T));
template<class T> T* Pool_alloc<T>::allocate(size_t n, void* = 0) {
   //...
   return p;
}
template<class T> void Pool_alloc<T>::deallocate(T* p, size_t n) {
   //...
}
main() {
  map<int, int, less<int>, Pool_alloc<pair<int, int> > > m;
  m[144] = 12;
  m.get_allocator().print_mm();  //doesn't work - it gives the wrong allocator :-(
}

接下来是这个例子的完整代码——它的基础取自著名的Bjarne Stroustrup的书

#include <iostream>
#include <memory>
#include <map>
using namespace std;
class Pool {
   struct Link {Link *next;};
   struct Chunk {
      static const unsigned size = 8192 - sizeof(Chunk*); //page boundary
      Chunk *next;
      char mem[size];
   } *chunks;
   Link *head;  //pointer to first free link
   Pool(Pool&);  //disable
   void operator=(Pool&); //disable
   void grow();
public:
   const unsigned int atomsize;
   Pool(unsigned n);  //n - number of atoms
   ~Pool();
   void* alloc();  //for one atom
   void free(void*);
   void print_mm();  //print pool memory map
};
void* Pool::alloc() {
   if (head == 0) grow();
   Link *p = head;
   head = p->next;
   return p;
}
void Pool::free(void *b) {
   Link *p = static_cast<Link*>(b);
   p->next = head;
   head = p;
}
Pool::Pool(unsigned sz): atomsize(sz < sizeof(Link*) ? sizeof(Link*) : sz) {
   cout << "atom size = " << atomsize << " bytesn";
   head = 0;
   chunks = 0;
}
Pool::~Pool() {
   Chunk *p = chunks;
   while (p) {
      Chunk *q = p;
      p = p->next;
      delete q;
   }
}
void Pool::grow() {
   Chunk *p = new Chunk;
   p->next = chunks;
   chunks = p;
   const unsigned noe = Chunk::size/atomsize;
   char *start = p->mem, *last = start + (noe - 1)*atomsize;
   for (char *p = start; p < last; p += atomsize)
      ((Link*)p)->next = (Link*)(p + atomsize);
   ((Link*)last)->next = 0;
   head = (Link*)start;
}
void Pool::print_mm() {
   cout << "The pool memory mapn";
   ///...
}
template<class T> class Pool_alloc : public allocator<T> {
   static Pool pool;  //static for STL
public:
   template<class U> struct rebind {
      typedef Pool_alloc<U> other;
   };
   template<class U> Pool_alloc(const Pool_alloc<U>&) {}
   Pool_alloc() {}
   T* allocate(size_t, void*);
   void deallocate(T*, size_t);
   static void print_mm() {pool.print_mm();}
};
template<class T> Pool Pool_alloc<T>::pool(sizeof(T));
template<class T> T* Pool_alloc<T>::allocate(size_t n, void* = 0) {
   T* p;
   if (n == 1)
      p = static_cast<T*>(pool.alloc());
   else
      p = static_cast<T*>(allocator<T>::allocate(n));    //STL level
      //p = static_cast<T*>(operator new (sizeof(T)*n));  //OS level
   return p;
}
template<class T> void Pool_alloc<T>::deallocate(T* p, size_t n) {
   if (n == 1)
      pool.free(p);
   else
      allocator<T>::deallocate(p, n);  //STL level
      //operator delete(p);  //OS level
}
main() {
   map<int, int, less<int>, Pool_alloc<pair<int, int> > > m;
   m.insert(pair<int,int>(7, 8));
   for (int i(0); i < 200; ++i)
      m[i*i] = 2*i;
   m.erase(169);
   m.erase(121);
   m[5] = 88;
   cout << m[7] << '-' << m[5] << '-' << m.size() << endl;
   m.get_allocator().print_mm();  //doesn't work - it gives the wrong allocator :-(
}

试试这个:

template<class T, Pool* pool> class Pool_alloc : public allocator<T> {
public:
  template<class U> struct rebind {
    typedef Pool_alloc<U, pool> other;
  };

这需要不同大小的Pool支持数据。

或者,用Pool<sizeof(T)>替换Pool,也许可以使用static方法技巧来分配singleton实例,然后您至少可以找到各种大小的分配器。(他们可以在一个全球游泳池中注册,这样你以后就可以找到他们了)。

然后,您的池分配器可以足够聪明,为请求的不同大小的数据使用不同大小的块。或者不,根据你的意愿。

相关文章: