程序中使用对象池可以避免创建和删除大量的对象。如果知道程序使用大量同类对象,而且这些对象执行时间又很短,则可以使用对象池
池技术。
下面是利用队列和向量实现的对象池代码:
Code
#include <queue>
#include <vector>
#include <stdexcept>
#include <memory>
using std::queue;
using std::vector;
//
// template class ObjectPool
//
// Provides an object pool that can be used with any class that provides a
// default constructor.
//
// The object pool constructor creates a pool of objects, which it hands out
// to clients when requested via the acquireObject() method. When a client is
// finished with the object it calls releaseObject() to put the object back
// into the object pool.
//
// The constructor and destructor on each object in the pool will be called only
// once each for the lifetime of the program, not once per acquisition and release.
//
// The primary use of an object pool is to avoid creating and deleting objects
// repeatedly. The object pool is most suited to applications that use large
// numbers of objects for short periods of time.
//
// For efficiency, the object pool doesn't perform sanity checks.
// Expects the user to release every acquired object exactly once.
// Expects the user to avoid using any objects that he or she has released.
//
// Expects the user not to delete the object pool until every object
// that was acquired has been released. Deleting the object pool invalidates
// any objects that the user had acquired, even if they had not yet been released.
//
template <typename T>
class ObjectPool
{
public:
//
// Creates an object pool with chunkSize objects.
// Whenever the object pool runs out of objects, chunkSize
// more objects will be added to the pool. The pool only grows:
// objects are never removed from the pool (freed), until
// the pool is destroyed.
//
// Throws invalid_argument if chunkSize is <= 0.
//
ObjectPool(int chunkSize = kDefaultChunkSize)
throw(std::invalid_argument, std::bad_alloc);
//
// Frees all the allocated objects. Invalidates any objects that have
// been acquired for use.
//
~ObjectPool();
//
// Reserve an object for use. The reference to the object is invalidated
// if the object pool itself is freed.
//
// Clients must not free the object!
//
T& acquireObject();
//
// Return the object to the pool. Clients must not use the object after
// it has been returned to the pool.
//
void releaseObject(T& obj);
protected:
//
// mFreeList stores the objects that are not currently in use
// by clients.
//
queue<T*> mFreeList;
//
// mAllObjects stores pointers to all the objects, in use
// or not. This vector is needed in order to ensure that all
// objects are freed properly in the destructor.
//
vector<T*> mAllObjects;
int mChunkSize;
static const int kDefaultChunkSize = 10;
//
// Allocates mChunkSize new objects and adds them
// to the mFreeList.
//
void allocateChunk();
static void arrayDeleteObject(T* obj);
private:
// Prevent assignment and pass-by-value
ObjectPool(const ObjectPool<T>& src);
ObjectPool<T>& operator=(const ObjectPool<T>& rhs);
};
template<typename T>
const int ObjectPool<T>::kDefaultChunkSize;
template <typename T>
ObjectPool<T>::ObjectPool(int chunkSize) throw(std::invalid_argument,
std::bad_alloc) : mChunkSize(chunkSize)
{
if (mChunkSize <= 0) {
throw std::invalid_argument("chunk size must be positive");
}
// Create mChunkSize objects to start
allocateChunk();
}
//
// Allocates an array of mChunkSize objects because that's
// more efficient than allocating each of them individually.
// Stores a pointer to the first element of the array in the mAllObjects
// vector. Adds a pointer to each new object to the mFreeList.
//
template <typename T>
void ObjectPool<T>::allocateChunk()
{
T* newObjects = new T[mChunkSize];
mAllObjects.push_back(newObjects);
for (int i = 0; i < mChunkSize; i++)
{
mFreeList.push(&newObjects[i]);
}
}
//
// Freeing function for use in the for_each algorithm in the
// destructor.
//
template<typename T>
void ObjectPool<T>::arrayDeleteObject(T* obj)
{
delete [] obj;
}
template <typename T>
ObjectPool<T>::~ObjectPool()
{
// free each of the allocation chunks
for_each(mAllObjects.begin(), mAllObjects.end(), arrayDeleteObject);
}
template <typename T>
T& ObjectPool<T>::acquireObject()
{
if (mFreeList.empty()) {
allocateChunk();
}
T* obj = mFreeList.front();
mFreeList.pop();
return (*obj);
}
template <typename T>
void ObjectPool<T>::releaseObject(T& obj)
{
mFreeList.push(&obj);
}
#include <queue>
#include <vector>
#include <stdexcept>
#include <memory>
using std::queue;
using std::vector;
//
// template class ObjectPool
//
// Provides an object pool that can be used with any class that provides a
// default constructor.
//
// The object pool constructor creates a pool of objects, which it hands out
// to clients when requested via the acquireObject() method. When a client is
// finished with the object it calls releaseObject() to put the object back
// into the object pool.
//
// The constructor and destructor on each object in the pool will be called only
// once each for the lifetime of the program, not once per acquisition and release.
//
// The primary use of an object pool is to avoid creating and deleting objects
// repeatedly. The object pool is most suited to applications that use large
// numbers of objects for short periods of time.
//
// For efficiency, the object pool doesn't perform sanity checks.
// Expects the user to release every acquired object exactly once.
// Expects the user to avoid using any objects that he or she has released.
//
// Expects the user not to delete the object pool until every object
// that was acquired has been released. Deleting the object pool invalidates
// any objects that the user had acquired, even if they had not yet been released.
//
template <typename T>
class ObjectPool
{
public:
//
// Creates an object pool with chunkSize objects.
// Whenever the object pool runs out of objects, chunkSize
// more objects will be added to the pool. The pool only grows:
// objects are never removed from the pool (freed), until
// the pool is destroyed.
//
// Throws invalid_argument if chunkSize is <= 0.
//
ObjectPool(int chunkSize = kDefaultChunkSize)
throw(std::invalid_argument, std::bad_alloc);
//
// Frees all the allocated objects. Invalidates any objects that have
// been acquired for use.
//
~ObjectPool();
//
// Reserve an object for use. The reference to the object is invalidated
// if the object pool itself is freed.
//
// Clients must not free the object!
//
T& acquireObject();
//
// Return the object to the pool. Clients must not use the object after
// it has been returned to the pool.
//
void releaseObject(T& obj);
protected:
//
// mFreeList stores the objects that are not currently in use
// by clients.
//
queue<T*> mFreeList;
//
// mAllObjects stores pointers to all the objects, in use
// or not. This vector is needed in order to ensure that all
// objects are freed properly in the destructor.
//
vector<T*> mAllObjects;
int mChunkSize;
static const int kDefaultChunkSize = 10;
//
// Allocates mChunkSize new objects and adds them
// to the mFreeList.
//
void allocateChunk();
static void arrayDeleteObject(T* obj);
private:
// Prevent assignment and pass-by-value
ObjectPool(const ObjectPool<T>& src);
ObjectPool<T>& operator=(const ObjectPool<T>& rhs);
};
template<typename T>
const int ObjectPool<T>::kDefaultChunkSize;
template <typename T>
ObjectPool<T>::ObjectPool(int chunkSize) throw(std::invalid_argument,
std::bad_alloc) : mChunkSize(chunkSize)
{
if (mChunkSize <= 0) {
throw std::invalid_argument("chunk size must be positive");
}
// Create mChunkSize objects to start
allocateChunk();
}
//
// Allocates an array of mChunkSize objects because that's
// more efficient than allocating each of them individually.
// Stores a pointer to the first element of the array in the mAllObjects
// vector. Adds a pointer to each new object to the mFreeList.
//
template <typename T>
void ObjectPool<T>::allocateChunk()
{
T* newObjects = new T[mChunkSize];
mAllObjects.push_back(newObjects);
for (int i = 0; i < mChunkSize; i++)
{
mFreeList.push(&newObjects[i]);
}
}
//
// Freeing function for use in the for_each algorithm in the
// destructor.
//
template<typename T>
void ObjectPool<T>::arrayDeleteObject(T* obj)
{
delete [] obj;
}
template <typename T>
ObjectPool<T>::~ObjectPool()
{
// free each of the allocation chunks
for_each(mAllObjects.begin(), mAllObjects.end(), arrayDeleteObject);
}
template <typename T>
T& ObjectPool<T>::acquireObject()
{
if (mFreeList.empty()) {
allocateChunk();
}
T* obj = mFreeList.front();
mFreeList.pop();
return (*obj);
}
template <typename T>
void ObjectPool<T>::releaseObject(T& obj)
{
mFreeList.push(&obj);
}
调用的代码:
Code
#include "ObjectPool.h"
class UserRequest
{
public:
UserRequest() {}
~UserRequest() {}
// Methods to populate the request with specific information.
// Methods to retrieve the request data.
// (not shown)
protected:
// data members (not shown)
};
UserRequest& obtainUserRequest(ObjectPool<UserRequest>& pool)
{
// Obtain a UserRequest object from the pool
UserRequest& request = pool.acquireObject();
// populate the request with user input
// (not shown)
return (request);
}
void processUserRequest(ObjectPool<UserRequest>& pool, UserRequest& req)
{
// process the request
// (not shown)
// return the request to the pool
pool.releaseObject(req);
}
int main(int argc, char** argv)
{
ObjectPool<UserRequest> requestPool(1000);
// Set up program
// (not shown)
while (true /* program is running */) {
UserRequest& req = obtainUserRequest(requestPool);
processUserRequest(requestPool, req);
}
return (0);
}
#include "ObjectPool.h"
class UserRequest
{
public:
UserRequest() {}
~UserRequest() {}
// Methods to populate the request with specific information.
// Methods to retrieve the request data.
// (not shown)
protected:
// data members (not shown)
};
UserRequest& obtainUserRequest(ObjectPool<UserRequest>& pool)
{
// Obtain a UserRequest object from the pool
UserRequest& request = pool.acquireObject();
// populate the request with user input
// (not shown)
return (request);
}
void processUserRequest(ObjectPool<UserRequest>& pool, UserRequest& req)
{
// process the request
// (not shown)
// return the request to the pool
pool.releaseObject(req);
}
int main(int argc, char** argv)
{
ObjectPool<UserRequest> requestPool(1000);
// Set up program
// (not shown)
while (true /* program is running */) {
UserRequest& req = obtainUserRequest(requestPool);
processUserRequest(requestPool, req);
}
return (0);
}