Professional C__ - Marc Gregoire [421]
An Object Pool Implementation
This section provides an implementation of a pool class template that you can use in your programs. The pool allocates a chunk of objects of the specified class when it is constructed and hands them out via the acquireObject() method. When the client is done with the object, she returns it via the releaseObject() method. If aquireObject() is called but there are no free objects, the pool allocates another chunk of objects.
The most difficult aspect of an object pool implementation is keeping track of which objects are free and which are in use. This implementation takes the approach of storing free objects in a queue. Each time a client requests an object, the pool gives that client the top object from the queue. The pool does not explicitly track objects that are in use. It trusts the clients to return them correctly to the pool when the clients are finished with them.
The code uses the queue class from the Standard Template Library (STL), discussed in Chapter 12. Memory for allocated objects is handled by shared_ptr smart pointers; see Chapter 21. When the pool allocates a new object, the new object is managed by a new shared_ptr which is added to the queue.
Here is the class definition, with comments that explain the details. Note that the template is parameterized on the class type from which the objects in the pool are to be constructed.
#include #include #include using std::queue; using std::shared_ptr; // 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. // It expects the user to release every acquired object exactly once. // It expects the user to avoid using any objects that he or she has released. template 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. // Throws bad_alloc if allocation fails. ObjectPool(size_t chunkSize = kDefaultChunkSize) throw(std::invalid_argument, std::bad_alloc); // Reserves an object for use. Clients must not free the object! shared_ptr // Returns the object to the pool. Clients must not use the object after // it has been returned to the pool. void releaseObject(shared_ptr protected: // mFreeList stores the objects that are not currently in use by clients. queue size_t mChunkSize; static const size_t kDefaultChunkSize = 10; // Allocates mChunkSize new objects and adds them to mFreeList. void allocateChunk(); private: // Prevent assignment and pass-by-value ObjectPool(const ObjectPool ObjectPool }; Code snippet from ObjectPool\ObjectPool.h Note that the user of the object pool specifies through the template parameter the name of the class from which objects can be created, and through the constructor the allocation “chunk size.” This “chunk size” controls