Professional C__ - Marc Gregoire [422]
template Code snippet from ObjectPool\ObjectPool.h The default of 10, given in the class definition, is probably too small for most uses. If your program requires thousands of objects at once, you should use a larger, more appropriate, value. The constructor validates the chunkSize parameter, and calls the allocateChunk() helper method to obtain a starting allocation of objects: template throw(std::invalid_argument, std::bad_alloc) { if (chunkSize == 0) { throw std::invalid_argument("chunk size must be positive"); } mChunkSize = chunkSize; // Create mChunkSize objects to start. allocateChunk(); } Code snippet from ObjectPool\ObjectPool.h The allocateChunk() method allocates mChunkSize elements. It stores a shared_ptr to each object in the queue: // Allocates mChunkSize new objects. template { for (size_t i = 0; i < mChunkSize; ++i) { mFreeList.push(std::make_shared } } Code snippet from ObjectPool\ObjectPool.h acquireObject() returns the top object from the free list, first calling allocateChunk() if there are no free objects: template { if (mFreeList.empty()) { allocateChunk(); } auto obj = mFreeList.front(); mFreeList.pop(); return obj; } Code snippet from ObjectPool\ObjectPool.h Finally, releaseObject() returns the object to the tail of the free list: template { mFreeList.push(obj); } Code snippet from ObjectPool\ObjectPool.h Using the Object Pool Consider an application that is structured around obtaining requests for actions from users and processing those requests. This application would most likely be the middleware between a graphical front-end and a back-end database. For example, it could be part of an airline reservation system or an online banking application. You might want to encode each user request in an object, with a class that looks something like this: class UserRequest { public: UserRequest() {} virtual ~UserRequest() {} // Methods to populate the request with specific information. // Methods to retrieve the request data. // (not shown) protected: // Data members (not shown) }; Code snippet from ObjectPool\ObjectPoolTest.cpp Instead of creating and deleting large numbers of requests throughout the lifetime of your program, you could use an object pool. Your program structure would then be something as follows: shared_ptr { // Obtain a UserRequest object from the pool. auto request = pool.acquireObject(); // Populate the request with user input. (not shown) return request; } void processUserRequest(ObjectPool shared_ptr { // Process the request. (not shown) // Return the request to the pool. pool.releaseObject(req); } int main() { ObjectPool cout << "Loop starting." << endl; for (size_t i = 0; i < 100; ++i) { auto req = obtainUserRequest(requestPool); processUserRequest(requestPool, req); } cout << "Loop finished." << endl; return 0; } Code snippet from ObjectPool\ObjectPoolTest.cpp PROFILING
Although we urge you to think about efficiency as you design and code, you should accept that not every finished application will perform as well as it could. It is easy for efficiency to fall by the wayside in an attempt to generate a functional program; in our experience, most efficiency optimization is performed on already working programs. Even if you did consider efficiency in your development, you might not have optimized the right parts of the program. Chapter 2 introduces the “90/10” rule: 90 percent of the running time of most programs is spent in only 10 percent of the code (Hennessy and Patterson,