使用 static allocator 达到复用效果

使用 static allocator, 可以不必像 per-class allocator 一样需要对每一个类都写好内存池的实现。

下面演示一种做法,每个allocator object 都是一个分配器,它内部维护一个 free lists,不同的 allocator objects 维护不同的链表

#include <cstddef>
#include <iostream>

using namespace std;

class myAllocator {
  private:
    struct obj {
      struct obj* next;  // 指向下一个元素的指针
    };
  public:
    void* allocate(size_t);
    void deallocate(void*, size_t);

  private:
    obj* freeStore = nullptr;
    const int CHUNK = 5;
};

void* myAllocator::allocate(size_t size) {
  obj* p;
  if (!freeStore) {
    size_t chunk = CHUNK * size;
    freeStore = p = (obj*) malloc(chunk);

    for (int i = 0; i < (CHUNK - 1); ++i) {
      p->next = (obj*)((char*)p + size);
      p = p->next;
    }
    p->next = nullptr;
  }
  p = freeStore;
  freeStore = freeStore->next;
  return p;
}

void myAllocator::deallocate(void* p, size_t) {
  ((obj*)p)->next = freeStore;
  freeStore = (obj*)p;
}

class Foo {
  public:
    long long l;  // 注意:这里如果数据的大小小于指针大小,即小于8个字节,会导致段错误
    static myAllocator myAlloc;  // 这里通过myAllocator来接管Foo的内存分配
  public:
    Foo(long long l) : l(l) {}
    static void* operator new(size_t size) { return myAlloc.allocate(size); }
    static void operator delete(void* pdead, size_t size) { return myAlloc.deallocate(pdead, size); }
};
myAllocator Foo::myAlloc;

int main() {

  cout << sizeof(Foo) << endl;

  size_t const N = 10;
  Foo *p[N];

  for (unsigned int i = 0; i < N; ++i) p[i] = new Foo(i);

  // 输出地址,比较其间隔
  for (unsigned int i = 0; i < N; ++i) cout << p[i] << endl;

  for (unsigned int i = 0; i < N; ++i) delete p[i];
}

<aside> 💡 需要注意的是,这样的写法并非线程安全的

</aside>

macro for static allocator

macro for static allocator 简单就是说,将部分制式代码使用宏的方式,这么可以避免写很多重复代码,如下所示

#include <cstddef>
#include <iostream>

using namespace std;

class myAllocator {
  private:
    struct obj {
      struct obj* next;  // 指向下一个元素的指针
    };
  public:
    void* allocate(size_t);
    void deallocate(void*, size_t);

  private:
    obj* freeStore = nullptr;
    const int CHUNK = 5;
};

void* myAllocator::allocate(size_t size) {
  obj* p;
  if (!freeStore) {
    size_t chunk = CHUNK * size;
    freeStore = p = (obj*) malloc(chunk);

    for (int i = 0; i < (CHUNK - 1); ++i) {
      p->next = (obj*)((char*)p + size);
      p = p->next;
    }
    p->next = nullptr;
  }
  p = freeStore;
  freeStore = freeStore->next;
  return p;
}

void myAllocator::deallocate(void* p, size_t) {
  ((obj*)p)->next = freeStore;
  freeStore = (obj*)p;
}

#define DECLARE_POOL_ALLOC() \\
  public: \\
    static void* operator new(size_t size) { return myAlloc.allocate(size); } \\
    static void operator delete(void* pdead, size_t size) { return myAlloc.deallocate(pdead, size); } \\
  protected: \\
    static myAllocator myAlloc; \\

#define IMPLEMENT_POOL_ALLOC(class_name) \\
myAllocator class_name::myAlloc;

class Foo {
  DECLARE_POOL_ALLOC()
  public:
    long long l;  // 注意:这里如果数据的大小小于指针大小,即小于8个字节,会导致段错误
  public:
    Foo(long long l) : l(l) {}
};
IMPLEMENT_POOL_ALLOC(Foo)

int main() {

  cout << sizeof(Foo) << endl;

  size_t const N = 10;
  Foo *p[N];

  for (unsigned int i = 0; i < N; ++i) p[i] = new Foo(i);

  // 输出地址,比较其间隔
  for (unsigned int i = 0; i < N; ++i) cout << p[i] << endl;

  for (unsigned int i = 0; i < N; ++i) delete p[i];
}