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
|
// $Id$
/* ---------------------------------------------------------------- */
/* Copyright 2005 (c) by RWTH Aachen - Lehrstuhl fuer Informatik VI */
/* Richard Zens */
/* ---------------------------------------------------------------- */
#ifndef OBJECTPOOL_H_
#define OBJECTPOOL_H_
#include <vector>
#include <deque>
#include <string>
#include <iostream>
#include <iterator>
// template class for pool of objects
// - usefull if many small objects are frequently created and destroyed
// - allocates memory for N objects at a time
// - separates memory allocation from constructor/destructor calls
// - prevents memory leak
template<typename T> class ObjectPool {
public:
typedef T Object;
private:
std::string name;
size_t idx,dIdx,N;
std::vector<Object*> data;
std::vector<size_t> dataSize;
std::deque<Object*> freeObj;
int mode;
public:
static const int cleanUpOnDestruction=1;
static const int hasTrivialDestructor=2;
// constructor arguments:
// N: initial number of objects to allocate memory at a time
// m & cleanUpOnDestruction = clean up objects in destructor
// m & hasTrivialDestructor = the object type has a trivial destructor,
// i.e. no sub-object uses dynamically allocated memory
// note: not equivalent to empty destructor
// -> more efficient (destructor calls can be omitted),
// note: looks like memory leak, but is not
ObjectPool(std::string name_="T",size_t N_=100000,int m=cleanUpOnDestruction)
: name(name_),idx(0),dIdx(0),N(N_),mode(m) {allocate();}
// main accesss functions:
// get pointer to object via default or copy constructor
Object* get() {return new (getPtr()) Object;}
Object* get(const Object& x) {return new (getPtr()) Object(x);}
// get pointer to uninitialized memory,
// WARNING: use only if you know what you are doing !
// usefull for non-default constructors, you have to use placement new
Object* getPtr() {
if(freeObj.size()) {
Object* rv=freeObj.back();freeObj.pop_back();rv->~Object();return rv;}
if(idx==dataSize[dIdx]) {idx=0; if(++dIdx==data.size()) allocate();}
return data[dIdx]+idx++;
}
// return object(s) to pool for reuse
// note: objects are not destroyed here, but in 'getPtr'/'destroyObjects',
// otherwise 'destroyObjects' would have to check the freeObj-stack
// before each destructor call
void freeObject(Object* x) {freeObj.push_back(x);}
template<class fwiter> void freeObjects(fwiter b,fwiter e) {
for(;b!=e;++b) this->free(*b);}
// destroy all objects, but do not free memory
void reset() {destroyObjects();idx=0;dIdx=0;freeObj.clear();}
// destroy all objects and free memory
void cleanUp() {
reset(); for(size_t i=0;i<data.size();++i) free(data[i]);
data.clear();dataSize.clear();
}
~ObjectPool() {if(mode & cleanUpOnDestruction) cleanUp();}
void printInfo(std::ostream& out) const {
out<<"OPOOL ("<<name<<") info: "<<data.size()<<" "<<dataSize.size()<<" "
<<freeObj.size()<<"\n"<<idx<<" "<<dIdx<<" "<<N<<"\n";
std::copy(dataSize.begin(),dataSize.end(),
std::ostream_iterator<size_t>(out," "));
out<<"\n\n";
}
private:
void destroyObjects() {
if(mode & hasTrivialDestructor) return;
for(size_t i=0;i<=dIdx;++i) {
size_t lastJ= (i<dIdx ? dataSize[i] : idx);
for(size_t j=0;j<lastJ;++j) (data[i]+j)->~Object();}
}
// allocate memory for a N objects, for follow-up allocations,
// the block size is doubled every time
// if allocation fails, block size is reduced by 1/4
void allocate() {
// std::cerr<<"start "<<name<<" - objectpool allocate "<<N<<"\n";
try {
if(dataSize.empty()) dataSize.push_back(N);
else dataSize.push_back(dataSize.back()*2);
void *m=malloc(sizeof(Object)*dataSize.back());
while(!m) {
// std::cerr<<"malloc failed for size "<<dataSize.back()<<"!\n";
dataSize.back()=static_cast<size_t>(dataSize.back()*0.75);
m=malloc(sizeof(Object)*dataSize.back());
}
data.push_back(static_cast<Object*>(m));
}
catch (const std::exception& e) {
std::cerr<<"caught std::exception: "<<e.what()
<<" in ObjectPool::allocate(), name: "<<name<<", last size: "
<<dataSize.back()<<"\n";
std::cerr<<"OPOOL info: "<<data.size()<<" "<<dataSize.size()<<" "
<<freeObj.size()<<"\n"<<idx<<" "<<dIdx<<" "<<N<<"\n";
std::copy(dataSize.begin(),dataSize.end(),
std::ostream_iterator<size_t>(std::cerr," "));
std::cerr<<"\n";
throw;
}
}
};
#endif
|