使用 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 简单就是说,将部分制式代码使用宏的方式,这么可以避免写很多重复代码,如下所示
#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];
}