僕が shared_ptr よりも retain() / release() 方式が好きだと思う理由

それは、shared_ptr のようなラッパーよりも、オブジェクト自体が参照カウンタをもっているほうがコードが書きやすいから。

たとえば、継承したクラスでオブジェクトの参照カウントをいじることは、shared_ptr では難しい。

shared_ptr を使った場合:

class Base {
public:
   virtual void foo() = 0;
};

class Derived : public Base {
public:
  virtual void foo() {
    // ここで自分自身への参照カウンタをインクリメントしたいけどできない…
    gManager_.register(this);
};

// 呼び出し側
obj = shared_ptr<Base>(new Derived());
obj->foo();

オブジェクト自体が参照カウンタをもっていれば、このような問題は発生しない。そして、コード量が増えているように見えるけど、参照カウントを管理するための mix-in クラスと CComPtr みたいなラッパーを用意すれば、コーディング量は実質ゼロにできる。

class Base {
  size_t refcnt_;
public:
  Base() : refcnt_(1) {}
  void retain() { refcnt_++; }
  void release() { if (--refcnt_ == 0) delete this; }
  virtual void foo() = 0;
};

class Derived : public Base {
public:
  virtual void foo() {
    retain(); // incr refcount to myself and register
    gManager_.register(this);
  }
};

// 呼び出し側
obj = new Derived();
derived->foo();

だから、「データ型」を扱う場合は shared_ptr でもいいけど、高レベルな処理を記述する「オブジェクト」については retain() / release() でいいんじゃないかと思ってる。