Online Book Reader

Home Category

Professional C__ - Marc Gregoire [422]

By Root 1378 0
the number of objects created at one time. Here is the code that defines the kDefaultChunkSize:

template const size_t ObjectPool::kDefaultChunkSize;

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 ObjectPool::ObjectPool(size_t chunkSize)

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 void ObjectPool::allocateChunk()

{

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 shared_ptr ObjectPool::acquireObject()

{

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 void ObjectPool::releaseObject(shared_ptr obj)

{

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 obtainUserRequest(ObjectPool& pool)

{

// Obtain a UserRequest object from the pool.

auto request = pool.acquireObject();

// Populate the request with user input. (not shown)

return request;

}

void processUserRequest(ObjectPool& pool,

shared_ptr req)

{

// Process the request. (not shown)

// Return the request to the pool.

pool.releaseObject(req);

}

int main()

{

ObjectPool requestPool(10);

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,

Return Main Page Previous Page Next Page

®Online Book Reader