不完全クラスのdeleteに注意

pImplイディオムを使っているところでメモリリークしていた。調べてみると、pImplクラスの解放をauto_ptrに任せていたのが原因らしい。orz

// Hoge.h
class Hoge
{
  Hoge();
private:
  struct pImpl;
  std::auto_ptr<pImpl> impl;
};

// Hoge.cpp
struct Hoge::pImpl
{
  ~pImpl() { std::cout << "Destructor" << std::endl; }
};

Hoge::Hoge() : impl(new pImpl){}

不完全クラスのdeleteは未定義なため*1、上記のような実装を行うと auto_ptr は pImpl のデストラクタを適切に呼び出してくれず、メモリリークが生じる事がある。

こういう用途に使う場合は boost::shared_ptr を使うと安全です。


pimplイディオムを語る

ありえるえりあ
で紹介されているコードでも、同じ問題が出そう。

あれ、VC8だとちゃんとデストラクタが呼ばれるな……なんでだろ。……どうやら Hoge のデストラクタが定義されていると、リンク時にうまいことやってくれる、っぽい?

// Hoge.h
class Hoge
{
  Hoge();
  ~Hoge(); // ここを追加
private:
  struct pImpl;
  std::auto_ptr<pImpl> impl;
};

// Hoge.cpp
struct Hoge::pImpl
{
  ~pImpl() { std::cout << "Destructor" << std::endl; }
};

Hoge::Hoge() : impl(new pImpl){}
Hoge::~Hoge() {} // ここを追加

デストラクタをインラインにするとうまくいかなくなる模様。よくわからないなぁ。なお bcc5.6.4 では、上記のようにしてもやっぱり駄目なようです。

追記

キーワード変えてぐぐったら超がいしゅつ(なぜか変換ry)でした><

shared_ptrからpimplのデストラクタ呼び出し - C・C++ - 教えて!goo

bccでうまくいかないのはバグかなー。

*1:参考:[http://hikarukaru.jugem.cc/?eid=99:title]