10

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、またはその他のトリックを使用して、可能な限り多くの定型コードを回避して、これをどのように改善しますか? 実行時のパフォーマンスは問題ではありません。

4

2 に答える 2

5

Lokiからのpimplの実装は良い答えかもしれません。これに関するDDJの記事も参照してください。

于 2010-03-01T08:28:15.753 に答える
1

それは可能ですが、素朴な実装はあなたが望むものではありません。

問題は、テンプレートが一般的にインライン化されていることです。単純な実装は次のようになります。

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実装することはできません...DestructorCopy ConstructorAssignment Operator

しかし、問題は解決できないほどではありません!Boostは確かにそれを解決しましたshared_ptr

アイデアは、コンストラクターで2番目の項目を渡すことです。これは、最初の項目のメモリーの解放を処理し、優れたデフォルトの実装で提供されます。

もちろん、これは間接参照で機能します。

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++の古典的なイディオムであり、さらに別のレベルの間接参照を追加します:)

于 2010-03-01T09:10:15.763 に答える