Завершите или реализуйте с самого начала Pool_alloc (параграф 19.4.2) так, чтобы обеспечивались все возможности стандартного аллокатора allocator (параграф 19.4.1) из стандартной библиотеки. Сравните производительности Pool_alloc и allocator, чтобы решить, стоит ли использовать Pool_alloc в вашей системе.
Пытался я разобраться в том коде что в книге, но так не сильно разобрался, как то не охота вникать, код как оказалось не такой и простой, что то там выделяется хз что. В общем закомментировал я его, он не заработал, вылазят ошибки, когда компилирую для vector или map, поэтому просто щас его скину, что бы не парится, не правильный он какой то, пока что отложу, возможно потом когда понадобится вернусь к нему.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
//Pool_alloc #include <iostream> using std::cout; using std::endl; #include <vector> using std::vector; #include <map> using std::map; #include <string> using std::string; #include <utility> using std::pair; #include <functional> using std::less; class Pool//переводится как басейн { struct Link{Link* next;}; struct Chunk//переводится как кусок { enum{size=8*1024-16};//слегка менше 8К, чтобы кусок памяти умещался в 8К char mem[size];//для достижения точного выравнивания Chunk* next;//указатель на следующий кусок }; Chunk* chunks;//указатель на куски const unsigned int esize;//размер элемента видимо в байтах, а мб хз. Link* head; //ссылка на голову //конструктор копирования Pool (Pool&); //защита от копирования //оператор присваивания void operator=(Pool&);//защита от копирования //увеличить басейн void grow();//увеличить пул public: //конструктор преобразования Pool(unsigned int n);//n это размер элементов ~Pool();//деструктор //выделяет память void* alloc();//выделить память под один элемент //освобождение памяти void free(void* b);//возвращение элемента в пул }; //функция выделения памяти //inline функция явно прописывается в коде без вызова //void* возвращает любой тип inline void* Pool::alloc() { //ессли начало рано ноль, то увеличить басейн if(head==0)grow(); Link* p=head;//вернуть первый элемент head=p->next; return p; } //освобождение памяти принимает любой указатель //похоже освобождение без уничтожения объекта inline void Pool::free(void* b) { //преобразование указателя в link Link* p=static_cast<Link*>(b);//грубое преобразование типа void* в тип Link* p->next=head;//член next = голова head=p;//голова равняется p указатель на Link* } //конструктор преобразования //sz-размер элемента Pool::Pool(unsigned int sz) :esize(sz<sizeof(Link)?sizeof(Link):sz)//если меньше то sizeof(Link), если больше то sz { head=0;//голова 0 chunks=0;//кусок 0 } Pool::~Pool()//освободить все куски (chunks) { Chunk* n=chunks; while(n)//пока n не 0 { Chunk* p=n; n=n->next;//сделанно в виде списка delete p;//освободить память } } void Pool::grow()//выделяет новый 'chunk', организуя его в виде связанного //списка элементов размером 'esize' { Chunk* n=new Chunk;//выделение нового куска n->next=chunks;//сначала равно 0, а затем уже видимо на следующий кусок ссылка chunks=n;//указатель присваивается на новый выделенный кусок //nelem=size из Chunk разделить на размер элемента //size=8*1024-16 8 килобайт вроде как чуть меньше //nelem это количество элементов которое видимо выделено может быть. const int nelem=Chunk::size/esize; //указатель на char* start (n->mem где mem это массив mem[size] иил mem[8*1024-16], примерно 8К) char* start=n->mem; //конец равен количеству элементов минус 1 и умноженое на размер элемента, это просто указатель на последний элемент char* last=&start[(nelem-1)*esize];//указывает похоже на элемент за последним //цикл от начала и до конца //памяти похоже сразу выделено 8К мы просто проходим по этой памяти //и делим, токо я не пойму как мы ее делим, p на начало указывает, p->next=p+esize, то есть указатель //плюс размер элемента, получается как то мы еще и по элементу пробигамем после того как мы к //p прибавили esize мы как бы переместили указатель и теперь он стал чуть дальше на esize //в общем мы просто тут похоже как бы формируем связаный список из кусков памяти размером esize. for(char*p=start;p<last;p+=esize) reinterpret_cast<Link*>(p)->next=reinterpret_cast<Link*>(p+esize); reinterpret_cast<Link*>(last)->next=0;//последний элемент списка равен 0 head=reinterpret_cast<Link*>(start);//первый элемент списка указывает на начало как бы связи //какой то этот код в понимании ни такой простой как кажется, даже после моей расписки что куда идет не сильно понятно } template<class T> class Pool_alloc { private: //статический член static Pool mem;//пул элементов размером sizeof(T) public: //аналогично стандартному аллокатору(19.4.1) typedef unsigned int size_type; typedef T* pointer; typedef unsigned int difference_type; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; Pool_alloc(); //конструктор копирования Pool_alloc(const Pool_alloc<T>& a):mem(a.mem){} T* allocate(size_type,void*); void deallocate(pointer p,size_type n); template<class Other> struct rebind{ typedef Pool_alloc<Other> other; }; }; //инициализация статического члена template<class T> Pool Pool_alloc<T>::mem(sizeof(T)); template<class T> Pool_alloc<T>::Pool_alloc(){} template<class T> T* Pool_alloc<T>::allocate(size_type n,void* k) { //если n==1, то мы вызываем mem.alloc if(n==1)return static_cast<T*>(mem.alloc()); //... } template<class T> void Pool_alloc<T>::deallocate(pointer p,size_type n) { if(n==1) { mem.free(p); return; } //... } int main() { cout <<"Pool alloc"<<endl; vector<int,Pool_alloc<int> >v; v.push_back(1); cout <<v[0]<<endl; map<string,int,less<int>/*,Pool_alloc<pair<const string,int> >*/ >m; //m["hellow"]=33; //m["world"]=40; //cout <<m["hellow"]<<m["world"]<<endl; return 0; } |
Я вообще надеюсь что не понадобится, щас попробуем просто свой аллокатор создать без всяких там Pool
Неохота мне голову морочит вот свой собственный аллокатор, подсмотрел реализацию на форуме.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include <iostream> using std::cout; using std::endl; #include <allocators> template<class T> class allocator : public std::allocator<T> { public: typedef allocator<T> base; void* allocate(typename base::size_type n, void* =0) { return malloc(n*sizeof(T)); } void deallocate(void* p) { free(p); } void construct(void* p, const T& value) { new (p) T(value); } void destuct(T* p) { p->~T(); } }; int main() { allocator<int> a; int* p; p=static_cast<int*>(malloc(7*sizeof(int))); int* p1=p; for(int i=0;i<7;i++) { a.construct(p,4); p++; } p=p1; for(int i=0;i<7;i++) { cout <<*p<<endl; p++; } a.deallocate(p1); return 0; } |
Щас еще подсмотрю реализацию, чтобы можно было использовать в стандартных контейнерах, там есть. От все таки получилось и для вектора создать аллокатор, опять же без посторонней помощи не обошлось, жаль конечно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#include <iostream> using std::cout; using std::endl; #include <allocators> #include <vector> using std::vector; template<class T> class allocator : public std::allocator<T> { public: typedef allocator<T> base; typename base::pointer allocate(typename base::size_type n, void* =0) { return static_cast<typename base::pointer>(malloc(n*sizeof(T))); } void deallocate(void* p) { free(p); } void construct(void* p, const T& value) { new (p) T(value); } void destuct(T* p) { p->~T(); } }; int main() { allocator<int> a; int* p; p=static_cast<int*>(malloc(7*sizeof(int))); int* p1=p; for(int i=0;i<7;i++) { a.construct(p,4); p++; } p=p1; for(int i=0;i<7;i++) { cout <<*p<<endl; p++; } a.deallocate(p1); vector<int,allocator<int> > v; v.push_back(5); cout <<v[0]<<endl; return 0; } |
[youtube]http://www.youtube.com/watch?v=_rsnNWAZde0[/youtube]