Wednesday, November 25, 2009

The Pimpl Pattern

Credit to Angelo (http://angelorohit.blogspot.com/2008/02/reducing-compile-times-in-large-c.html).

The Private Implementation (Pimpl) pattern allows the implementation of a whole interface without the need to recompile the modules which use it. As with most design patterns, this pattern can best be explained with an example. Let's say that we have a class named Student. Our Student class is very popular in our project because many other classes use it. The header file of the Student class, "Student.h" may be as follows:
#ifndef STUDENT_HEADER
#define STUDENT_HEADER

#include

class Student
{
private:
std::string m_name;
};

#endif

We may have many classes that contain instances of Student. For example, a Subject class may have an aggregation of Students. So, each of the classes that contain Student(s) would probably have to include "Student.h". Now let's say that at some point in time, colleges allow students to carry mobile phones freely (I know that's not likely. :D). Now, our Student will have a contact number that we might want to record. Professors already had mobiles all along. So, let's say that we already have a class named ContactNo that stores all types of numbers, be they Landline, Mobile or Pagers. "Student.h" becomes...
#ifndef STUDENT_HEADER
#define STUDENT_HEADER

#include
#include "ContactNo.h"

class Student
{
private:
std::string m_name;
ContactNo m_contactNo;
};

#endif

After making the relevant changes, we need to do a full re-compile of the source. To our dismay, we might find that the compile time has become unbearably long. Why? It's because we included "Contact.h" in our popular "Student.h". With that one simple change, the header files of all the classes that used to just include "Student.h" will now also include "Contact.h". If our Student was that popular, then this might mean a lot of unnecessary inclusions. To add insult to injury, the contact number of the Student might never even be used by many classes. For example, our Subject class would have no reason to know the contact number of the Students who take that subject. That's why m_contactNo is a private member of Student. You might think that the entire situation is a bit contrived but I assure you its not and there can be situations where you might desperately be seeking a way to reduce compile times, especially in the case of large projects. This is where the Pimpl pattern comes in. Basically, what we need to somehow achieve is the removal of "ContactNo.h" from "Student.h". What we do is take the private implementation of the class (in our case, m_contactNo of Student) and pack it into a simple internal structure. A pointer to this structure, called an opaque pointer or d-pointer is then made a private member of the class. We also need to take care of dynamically creating and destroying the implementation structure for every object of the wrapping class.

This is then our "Student.h" file with the Pimpl pattern.
#ifndef STUDENT_HEADER
#define STUDENT_HEADER

#include

class Student
{
private:
std::string m_name;
struct PIMPL; //Forward declaration.
PIMPL* pimpl; //The opaque pointer.

public:
Student();
~Student();
};

#endif

Our "Student.cpp" file could be:
#include "Student.h"
#include "ContactNo.h"

//Private Implementation structure.
struct Student::PIMPL
{
ContactNo m_contactNo;
};

Student::Student()
{
pimpl = new PIMPL;
}

Student::~Student()
{
if(pimpl)
delete pimpl;
}

If we want to access the contact number of the student internally we do it as pimpl->m_contactNo. Morever, we can use the auto_ptr to eliminate the object deletion in the destructor of student class. Here is an exmaple:

http://www.codeproject.com/KB/tips/PIMPL.aspx

Now that we've seen how useful the Pimpl pattern can be, let's talk about its downside. By using the Pimpl pattern, our code has become a little more complex (less readable anyway) and we've also got to do a dynamic allocation for every instance of Student that is created. For large objects with relatively fewer instances, this probably won't be an issue but for small objects with several instances, Pimpl may not fit the bill.

Tuesday, November 18, 2008

My first blog... :) I know, I know, it is little late, but I start it anyway :)

To get some tips and useful information in everyday life..

I may focus on some aspects like:

- Programming;

- Travels;

- Financial News/Events;
....

Happy blogging..... ^_*