上一章实现的两个 allocator 必须为不同的 classes 重写一遍简直雷同的 member operator new 和 member operator delete,应该有办法将一个总是调配特定尺寸块的 memory allocator 概念包装起来,使它容易被重复使用。
以下展现一种形式,每个 allocator object 都是个分配器,它保护一个 free-list;不同的 allocator objects 保护不同的 free-list。

#include <iostream>#include <cstdlib>#include <string>#include <complex>using std::string;using std::complex;using std::cout;using std::endl;class allocator{private:    struct obj {        struct obj *next; // embedded pointer    };public:    void *allocate(size_t);    void deallocate(void*, size_t);private:    obj *freeStore = nullptr;    const int CHUNK = 5;  // 小一些不便察看};// 操作系统会尽量保障每次申请 CHUNK * size 内存时是间断的, 但两次之间无此承诺void *allocator::allocate(size_t size){    obj *p;    if (!freeStore)    {        // linked list 为空,于是申请一大块内存        size_t chunk = CHUNK * size;        freeStore = p = static_cast<obj*>(malloc(chunk));        // 将调配得来的一大块当作 linked list 般,小块小块串起来        for (int i=0; i<(CHUNK-1); ++i)        {            p->next = reinterpret_cast<obj*>((char*)p + size);            p = p->next;        }    }    p = freeStore;    freeStore = freeStore->next;    return p;}void allocator::deallocate(void* p, size_t){    // 将 *p 发出插入 free list 前端    static_cast<obj*>(p)->next = freeStore;    freeStore = static_cast<obj*>(p);}//=========================class Foo {public:    long L;    static allocator myAlloc;public:    Foo(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);    }};allocator Foo::myAlloc;class Goo {public:    complex<double> c;    string str;    static allocator myAlloc;public:    Goo(const complex<double> &x) : c(x)    { }    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);    }};allocator Goo::myAlloc;void func_1(){    Foo *p[100];    cout << "sizeof(Foo) = " << sizeof(Foo) << endl;    for (size_t i=0; i<23; ++i)    {        if (i != 0 && i % 5 == 0)            cout << endl;        p[i] = new Foo(i);        cout << p[i] << ' ' << p[i]->L << endl;    }    for (int i=0; i<23; ++i)        delete  p[i];}void func_2(){    Goo *p[100];    cout << "sizeof(Foo) = " << sizeof(Goo) << endl;    for (size_t i=0; i<17; ++i)    {        if (i != 0 && i % 5 == 0)            cout << endl;        p[i] = new Goo(complex<double>(i, i));        cout << p[i] << ' ' << p[i]->c << endl;    }    for (int i=0; i<17; ++i)        delete  p[i];}int main(){    func_1();    cout << "============" << endl;    func_2();    return 0;}

输入:[留神察看每五次输入之间,地址的连续性]

sizeof(Foo) = 40xeb80e8 00xeb80ec 10xeb80f0 20xeb80f4 30xeb80f8 40xeb8108 50xeb810c 60xeb8110 70xeb8114 80xeb8118 90xeb8128 100xeb812c 110xeb8130 120xeb8134 130xeb8138 140xeb8148 150xeb814c 160xeb8150 170xeb8154 180xeb8158 190xeb8168 200xeb816c 210xeb8170 22============sizeof(Foo) = 400xeb8188 (0,0)0xeb81b0 (1,1)0xeb81d8 (2,2)0xeb8200 (3,3)0xeb8228 (4,4)0xeb8258 (5,5)0xeb8280 (6,6)0xeb82a8 (7,7)0xeb82d0 (8,8)0xeb82f8 (9,9)0xeb8408 (10,10)0xeb8430 (11,11)0xeb8458 (12,12)0xeb8480 (13,13)0xeb84a8 (14,14)0xeb84d8 (15,15)0xeb8500 (16,16)

这比先前的设计洁净多了, application classed 不再与内存调配细节纠缠不清,所有相干细节都让 allocator 去操心,咱们的工作是让 application classes 正确工作。