COMFRK 無料です

例えば Win32 Crypt API の CryptProtectData なんですけど、

DATA_BLOB output;
::CryptProtectData(&input, desc, NULL, NULL, NULL, 0, &output);
shared_ptr<BYTE> ptr(output.pbData, ::LocalFree);

カスタムデリーターを使えば、オブジェクトをうっかり開放し損ねる、という悲劇を避けられてやったねなんですけど、これと対になる CryptUnprotectData なんですけど、

LPWSTR desc;
DATA_BLOB output;
::CryptUnprotectData(&input, &desc, NULL, NULL, NULL, 0, &output);
shared_ptr<BYTE> ptr(output.pbData, ::LocalFree); // can throw!
shared_ptr<remove_pointer<LPWSTR>::type> ptr_(desc, ::LocalFree);

アチャー。複数開放しないといけないリソースを返してくれる API は困ります。

そこで variadic template なんですけど、

auto f() -> void { }
template <typename P, typename D, typename... R>
auto f(const P& p, const D& d, R... r) -> void { d(p); f(r...); }

template <typename... T> struct s;
template <> struct s<> { typedef tuple<> type; };
template <typename P, typename D, typename... R>
struct s<P, D, R...> {
  typedef
    decltype(
      tuple_cat(declval<tuple<shared_ptr<typename remove_pointer<P>::type>>>(),
                declval<typename s<R...>::type>()))
    type;
};

auto g() -> tuple<> { return make_tuple(); }
template <typename P, typename D, typename... R>
auto g(const P& p, const D& d, R... r) -> typename s<P, D, R...>::type {
  shared_ptr<typename remove_pointer<P>::type> ptr;
  try {
    ptr.reset(p, d);
  } catch (...) {
    f(r...); throw;
  }
  auto t = g(r...);
  return tuple_cat(make_tuple(ptr), t);
}

グエーッこんな気持ちの悪いコードを書くんじゃない!大人は try catch を素直に使いましょう。

LPWSTR desc;
DATA_BLOB output;
::CryptUnprotectData(&input, &desc, NULL, NULL, NULL, 0, &output);
shared_ptr<BYTE> ptr;
try {
  ptr.reset(output.pbData, ::LocalFree);
} throw (...) {
  ::LocalFree(desc); throw;
}
shared_ptr<remove_pointer<LPWSTR>::type> ptr_(desc, ::LocalFree);

おしまい。


そんなわけで COMFRK vol1 の pdf がウェッブでダウンロードできるようになりましたから、読みましょう。
http://ratiwo.blogspot.com/2011/02/comfrk-free-dl.html

追記:サンプルコード gcc-4.5 でコンパイル通るようにしました。