Реализация pImpl с минимальным количеством кода - PullRequest
10 голосов
/ 01 марта 2010

Какие приемы можно использовать для минимизации рабочей нагрузки по реализации классов pImpl?

Заголовок:

class Foo {
    struct Impl;
    boost::scoped_ptr<Impl> self;
public:
    Foo(int arg);
    ~Foo();
    // Public member functions go here
};

Реализация:

struct Foo::Impl {
    Impl(int arg): something(arg) {}
    // All data members and private functions go here
};

Foo::Foo(int arg): self(new Impl(arg)) {}
Foo::~Foo() {}

// Foo's public functions go here (and they refer to data as self->something)

Как быулучшить это, используя Boost, возможно наследование, CRTP или другие приемы, чтобы избежать как можно большего количества стандартного кода?Производительность во время выполнения не является проблемой.

Ответы [ 2 ]

5 голосов
/ 01 марта 2010

Реализация pimpl из Loki может быть хорошим ответом. См. Также статью DDJ по этому вопросу.

1 голос
/ 01 марта 2010

Это возможно, но наивная реализация - это не то, что вам нужно.

Проблема в том, что шаблоны обычно встроены, наивная реализация будет выглядеть так:

template <class Object>
class Pimpl
{
public:
  explicit Pimpl(Object* obj): mObject(obj) {}
  ~Pimpl() { delete mObject; }

  // either deep copy or no copy
private:
  Object* mObject;
};

Теперь проблемав том, что вы не хотите, чтобы Object был известен в вашем заголовочном файле в целом (не для двоичной совместимости, а для управления зависимостями).А если Object неизвестно, то вы не можете напрямую реализовать Destructor, Copy Constructor и Assignment Operator ...

Однако проблема далеко не решаема!Boost действительно решил эту проблему для shared_ptr.

Идея состоит в том, чтобы передать второй элемент в конструктор, который позаботится об освобождении памяти первого, и ему будет предоставлен хороший стандарт по умолчанию.реализация.

Конечно, это работает с косвенным указанием.

namespace detail {
  template <class Object>
  struct Deleter { virtual void do(Object*) = 0; };
}

template <class Object>
class Pimpl
{
public:
  typedef detail::Deleter<Object> deleter_type;
  typedef boost::shared_ptr<deleter_type> deleter_pointer;

  Pimpl(std::auto_ptr<Object> obj, deleter_pointer del);
  ~Pimpl();
  Pimpl(const Pimpl&);
  Pimpl& operator(const Pimpl&);

private:
  Object* mObject;
  deleter_pointer mDeleter;
};

Это классическая идиома в C ++, добавьте еще один уровень косвенного обращения:)

...