The Pimpl Idiom

Thameera Senanayaka

Allion Technologies

aka Opaque Pointer or Cheshire Cat

A look at ABI

  • ABI - Application Binary Interface
  • Interface between two program modules, at the level of machine code

ABI covers:

  • The sizes, alignment, layout of data types
  • How fn arguments are passed, etc
  • C++ name mangling
  • etc

The header file defines ABI

  • A change to a header file breaks ABI
  • Recompile!

Caveat

  • Even adding/deleting a private member can break ABI just as public members/functions.

Also

  • Exposes implementation details to third parties

How to design a class which is as binary compatible as possible?

And as private as possible.

Pimpl Idiom

  • Pointer to the Implementation
  • Keep all details of implementation outside header file
  • Implementation details go in a private class
  • Keep a pointer to the private class in header
  • Class forwarding

Basically, the API class contains:

  • API methods
  • A private pointer to the implementation

Old way

class Image
{
public:
  Image();
  virtual ~Image();

  int crop();
  int setBrightness(int x);

private:
  void resize(int x, int y);

  unsigned char* imgData;
  unsigned int w, h;
};

Pimpl Idiom - Header

class Image
{
public:
  Image();
  virtual ~Image();

  int crop();
  int setBrightness(int x);

private:
  class Impl;
  Impl* _impl;
};

Pimpl Idiom - Implementation

class Image::Impl
{
public:
  int crop() { /*  */ }
  int setBrightness() { /*  */ }

private:
  void resize(int x, int y) { /*  */ }

  void* imageData;
  unsigned int w, h;
};

Image::Image : _impl(new Impl()) {
}

Image::~Image {
  if (_impl)
    delete _impl;
}

int Image::crop() {
  return _impl->crop();
}

int Image::setBrightness(int x) {
  return _impl->setBrightness(x);
}

Adding pointer semantics

class Image
{
  /* ... */

  bool operator==(Image const& that) const { return _impl == that._impl; }
  bool operator!=(Image const& that) const { return !operator==(that); }
  operator bool() const { return impl_; }

  /* ... */
};

Other operators

class Image
{
public:
  /* ... */

  Image(const Image&);            // copy ctor
  Image& operator=(const Image&); // copy assignment operator

  /* ... */
};

C++11 goodness

  • Use a std::unique_ptr for _impl
  • No need to destroy manually
class Image
{
public:
  /* ... */

private:
  class Impl;
  std::unique_ptr<Impl> _impl;
};

Pros of Pimpl

  • Really hide the private parts
  • ABI isn't broken unless public API is changed
  • Lesser dependencies for the header file (why?)
  • Faster compilation times (why?)

Cons of Pimpl

  • Overhead of a pointer call
  • Extra heap allocation

Thank you!

Made with Slides.com