本物の C++er はデストラクタを書かない

代わりに std::unique_ptr (あるいは boost::scoped_ptr )を使います.
何故か?

struct hoge
{
  hoge()
   : xxx( get_resource() )
  {
    /* 処理 */
    if( some_cond ) throw some_exception();
    /* さらに処理 */
  }
  ~hoge() throw(){ release_resource(xxx); }

  /* ... */

 private:
  XXX xxx;
};

このようなコードで,コンストラクタ中に例外が投げられた場合,
デストラクタが呼ばれず,解放漏れが起きるからです.


このような露骨な場合でなくても,

struct hoge
{
  hoge()
   : xxx( get_resource() ),
     yyy() // ここで例外!
  {
  }
  ~hoge() throw(){ release_resource(xxx); }

  /* ... */

 private:
  XXX xxx;
  YYY yyy;
};

とか,普通にありえる状況ではないでしょうか.


一般に,コンストラクタ中で例外が投げられた場合,そのクラスのデストラクタは呼ばれません.
しかし,そのような場合でも,既に初期化されたメンバのデストラクタは呼ばれます.
故に,デストラクタを使うクラスは,可能な限り,小さなクラスにするべきで,
その「可能な限り小さなクラス」の代表例が, std::unique_ptr なのです.

// リソース開放用ファンクタ
struct XXX_releaser
{
  typedef XXX pointer;
  void operator( XXX xxx ){ release_resource(xxx); }
};
// unique_ptr に typedef する
typedef std::unique_ptr<XXX, XXX_releaser> XXX_pointer;

// リソース取得関数は unique_ptr を返すようにすると良い
// 今回はラッパなので微妙だが
inline XXX_pointer get_xxx()
{
  return XXX_pointer( get_resource() );
}

// 本体
struct hoge
{
  hoge()
   : xxx( get_xxx() ), yyy()
  {
  }
  // デストラクタは書かない

  /* ... */

 private:
  XXX_pointer xxx;
  YYY yyy;
};

実際,殆どの場合で,デストラクタは std::unique_ptr に置き換え可能です.
故に繰り返します. 本物のC++erはデストラクタをイチイチ書きません.
これからは std::unique_ptr を使いましょう.