SAFE_RELEASE MUST DIE

`SAFE_RELEASE`/`SAFE_DELETE`を知らない人々は幸いである。


# SAFE_RELEASE MUST DIE
こんな感じのマクロ：

```cpp:wtf.cpp
// "安全な"COMポインタの解放処理マクロ
#define SAFE_RELEASE(p) if(p){ p->Release(); p=NULL; }

// "安全な"配列の解放処理マクロ
#define SAFE_DELETE(p) if(p){ delete[] p; p=NULL; }
```

あくまでC++言語のお話。C言語？知らない子ですね。
C言語でCOMを操作するとか、[きがくるっとる](https://gist.github.com/yohhoy/3053385)。

## 慈悲は無い
`SAFE_RELEASE`や`SAFE_DELETE`、またはそれに類するマクロは、**絶対に**使わないこと。

見た目だけC++ templateに変えても(`SafeRelease`)、**本質的には同じ**である。何も改善していない。**絶対に**使わないこと。

- 嬉々としてこのマクロを紹介するWebサイトを見かけたら、インターネット回線を切断してからWebブラウザを閉じ、該当サイトURLをブロックリストに追加しましょう。
- このマクロを使っているソースコードを見かけたら、エディタをそっと閉じてPCに向かって清めの塩をまき、ファイルをランダムデータで3回上書きしてから削除しましょう。
- このマクロを使っているプログラマを見かけたら、&lt;censored&gt;。

あと、MSDNはいい加減に[なんとかしてくれ](https://msdn.microsoft.com/en-us/library/windows/desktop/dd743946.aspx)。[C++ templateに変えた](https://msdn.microsoft.com/en-us/library/windows/desktop/dd940435.aspx)からといって、決して[許される](https://msdn.microsoft.com/ja-jp/magazine/dn904668.aspx)ものでは無い。[この誤訳](https://msdn.microsoft.com/ja-jp/library/ff485839.aspx)に至っては、翻訳者は[&lt;censored&gt;](https://twitter.com/yohhoy/status/495101821287813123)

## スマートポインタ is awesome.
腐臭漂うC時代の負債マクロではなく、C++コンパイラやC++ライブラリが提供する「**スマートポインタ(Smart Pointer)**」を利用すること。絶対に。

COMオブジェクト参照カウントのリリース(`IUnknown::Release()`)を行いたければ、以下のスマートポインタが利用できます。

- Active Template Library(ATL)の [`CComPtr`クラス](https://msdn.microsoft.com/ja-jp/library/ezzw7k98.aspx), [`CComQIPtr`クラス](https://msdn.microsoft.com/ja-jp/library/wc177dxw.aspx)
- Visual C++コンパイラ組込の [`_com_ptr_t`クラス](https://msdn.microsoft.com/ja-jp/library/417w8b3b.aspx)
- Boost.Smart Pointersライブラリの [`intrusive_ptr`クラス](http://www.boost.org/libs/smart_ptr/intrusive_ptr.html)

動的確保された配列の解放(`delete[]`)を行いたければ、以下のスマートポインタが利用できます。

- C++11標準ライブラリの [`unique_ptr`クラス](http://cpprefjp.github.io/reference/memory/unique_ptr.html)
- Boost.Smart Pointersライブラリの [`scoped_array`クラス](http://www.boost.org/libs/smart_ptr/scoped_array.htm), [`shared_array`クラス](http://www.boost.org/libs/smart_ptr/shared_array.htm)

というより、動的配列を確保している大半のケースでは、単にC++標準コンテナ [`std::vector`クラス](http://cpprefjp.github.io/reference/vector.html) で間に合います。

- 有効要素数(`size()`)とバッファ容量(`capacity()`)という属性情報を、セットで管理しています。動的配列ではプログラマの責任で別途管理が要りますが、面倒くさいしバグの温床にしかなりません。
- `std::vector<T>`の全要素は、連続したメモリ領域に配置されると保証されています。例えば`T=char`とすれば汎用の「メモリバッファ」として使えます。
- `operator[]`を介した要素アクセスコストまで気にするなら、走査直前に`T* ptr = &vec[0];`とでもして`ptr[n]`アクセスすればゼロオーバーヘッドになります。

# 感情論はこれくらいにして、理性的な解説も

`SAFE_RELEASE`マクロは、何がどう駄目なのかを列挙していきます。よくありそうなCOMクライアントコードを考えます。

```cpp:legacy_macro.cpp
bool my_func()
{
  ISomething *pObj = NULL;
  IFoo       *pFoo = NULL;
  HRESULT    hr;

  // Somethingクラスを作成（ISomethingインターフェイス取得）
  hr = CreateComObject(CLSID_Something, &pObj);
  // (戻り値hrチェック省略)

  // IFooインターフェイスを取得
  hr = pObj->QueryInterface(IID_Foo, &pFoo);
  if (FAILED(hr)) {
    // 関数を抜ける前にはReleaseを忘れずに！
    SAFE_RELEASE(pObj);
    return false;
  }

  // 別関数another_funcを呼び出し
  if (!another_func(pFoo)) {
    // 関数を抜ける前にはReleaseを忘れずに！
    SAFE_RELEASE(pFoo);
    SAFE_RELEASE(pObj);
    return false;
  }
  // まだまだ処理が続くよ...

  // 関数を抜ける前にはReleaseを忘れずに！
  SAFE_RELEASE(pFoo);
  SAFE_RELEASE(pObj);
  return true;
}
```

ATL提供のスマートポインタを使うと、次のように書けます：

```cpp:modern_sp.cpp
#include <atlbase.h>

bool my_func()
{
  // Somethingクラスを作成（ISomethingインターフェイス取得）
  CComPtr<ISomething> pObj;
  HRESULT hr = CreateComObject(CLSID_Something, &pObj);
  // (戻り値hrチェック省略)

  // IFooインターフェイスを取得
  CComQIPtr<IFoo, &IID_Foo> pFoo = pObj;
    // QueryInterfaceが呼び出される
  if (!pFoo)
    return false;  // 自動的にReleaseされる

  // 別関数another_funcを呼び出し
  if (!another_func(pFoo)) {
    return false;  // 自動的にReleaseされる
  }
  // まだまだ処理が続くよ...

  return true;  // 自動的にReleaseされる
}
```

1. マクロ版では結局**プログラマの責任**で、関数`return`の直前で解放処理を記述しなければなりません。コード構造が変更されたり、新しいインターフェイスが追加された時に、対応する解放処理の追記を忘れるとリソースリークします。スマートポインタ版では自動的に解放してくれます。
2. マクロ版は**例外安全ではありません**。`another_func()`や後続処理からC++例外が送出されて関数`my_func`を抜ける場合、インターフェイスはReleaseされずにリソースリークします。スマートポインタ版では例外による関数脱出であっても安全です。
3. マクロ版はスマートポインタ版に比べて、本質的な処理コードに対するBookkeepingコードの比率が高くなり、ソースコードの**"ノイズ"が増えます**。コードの可読性が低くなることで、保守性・拡張性にも悪影響を与えます。
4. C++を使っているのですから、変数宣言を関数先頭で行うのではなく。**代入するタイミングで宣言**すべきです。変数スコープを必要最小限に限定することは、ソースコードの可読性／保守性／拡張性を改善し向上させます。（マクロ版でも実施可能ですが、レガシーコードでは大抵C言語スタイル、つまり関数先頭で一括宣言するケースが多いようです。）