- Aniketh Girish


Hello folks,

While GSoC under progress, I'm learning new stuff inside the codebase of our application Krita and the library KNewStuff. While, integrating this framework, I came across a wonderful piece of technique written down in the library and tackle different problems like binary compatibility and optimization and all.

So it is called d-pointer. So let's start.

d-pointer implementation is a part of design pattern is also called opaque pointers. the opaque pointer is a special case of an opaque datatype, a datatype declared to be a pointer to a record or data structure of some unspecified type. Opaque pointers are a way to hide the implementation details of an interface from ordinary clients, so that the implementation may be changed without the need to recompile the modules using it. This benefits the programmer as well since a simple interface can be created, and most details can be hidden in another file. This is important for providing binary compatibility in libraries.

In short, binary compatibility means that when you change your class, you do not need to recompile classes that use it. Binary-code compatibility is a property of computer systems meaning that they can run the same executable code. Binary compatibility is a major benefit when developing computer programs that are to be run on multiple OSes.

In short, again, d-pointer is something which hides some certain implementation details of a library from the user and changes to the implementation can be made to a library without breaking binary compatibility.

At times by adding a new data member, we ended up changing the size of the class object. And it crashes (Happens only when the library is released and we change things inside). This is because when your C++ compiler generates code, it uses offsets to access data within an object.

In summary, never change the size or layout (don't move the data around) of exported (i.e visible to the user) C++ classes once your library has been released. A C++ compiler generates code assuming that the size or the ordering of data in a class does not change after the application has been compiled.

Here comes the d-pointer into action. The trick is to keep the size of all public classes of a library constant by only storing a single pointer. This pointer points to a private/internal data structure that contains all the data. The size of this internal structure can shrink or grow without having any side-effect on the application because the pointer is accessed only in the library code and from the application's point of view the size of the object never changes, it's always the size of the pointer. This pointer is called the d-pointer.

Let me give some examples for the implementation for the d-pointer.

Let's create a class called Crap :P

#1: Crap.h

class CrapPrivate;

class Crap { // ... void addCrap() const; // ...

private: CrapPrivate \*d; };

Now, all the implementation details for the d-pointer comes under the private header of the Crap class. (Private header in the sense Crap_p.h) which will be having a class/struct called CrapPrivate. Here I will illustrate with structure.

#2: Crap_p.h

struct CrapPrivate { double add; String CrapString; };

Now let's see how the class definition will be.

#2: Crap.cpp

// With this #include, we can access WidgetPrivate. #include "Crap_p.h"

Crap::Crap() : d(new CrapPrivate) { // Creation of private data }

void Crap::addCrap() const { // The d-pointer is only accessed in the library code return d->add; }

Thus, this helps in libraries to be deployed/released without needing some re-compilation, which will keep the binary compatibility integrated.

Other functionality of using d-pointer.

It's not all about binary compatibility. The d-pointer has other benefits:

  • Hide implementation details - We can ship Libs with just the header files and the binaries. The .cpp files can be closed source.
  • The header file is clean of implementation details and can serve as the API reference.
  • Since the header files needed for implementation are moved from the header file into the implementation (source) file, compiles are much faster.

That's all, for now, people, will be back with more.

Cheers. :D