2013年10月24日木曜日

[c++11] finallyみたいなことしたいけど、専用のRAIIクラス作るの嫌なんだけど・・・

c++には、javaみたいなfinallyがないんだけど、あーゆーの欲しいなーとおもって調べてみると、結局、

RAII用のクラス作れよ
boost/scope_exit使えよ

ということのようだ、前者はそれ用のクラス毎回作るのもなんだかなーだし、後者はちょっとぐじゃぐじゃしてて嫌だった。

頭に来たので、RAII用にshared_ptrを流用することにしたので、以下にメモっておく。
あ、c++11必須ね。
#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>

using namespace std;
#define FINALLY(CLAUSE) shared_ptr<void> f_i_n_a_l_l_y(nullptr, [&](void*){CLAUSE});

class SomeResource {
public:
 void open() {cout << "some resource open." << endl;}
 void close() {cout << "some resource close." << endl;}
};

int main() {
 try {
  SomeResource res;
  FINALLY(
    res.close();
  )

  res.open();
  cout << "before throw exception." << endl;
  throw runtime_error("xxx error.");
  cout << "end of try block." << endl;
 } catch (runtime_error &e) {
  cout << "Error: " << e.what() << endl;
 }
 cout << "out of try block." << endl;
}
実行した結果は、
some resource open.
before throw exception.
some resource close.
Error: xxx error.
out of try block.
マクロ使って少し見やすくしました。
注意点は、FINALLYを解放したいリソースの宣言と例外が出る可能性のある場所の「間」に入れるところです。

こう見ると、shared_ptrのカスタムデリーターって、いろんなことに流用できそうですね。ちゃんとカウント取ってるからそこの一部のスコープだけに限らず使えるし。
後処理という発想だけでなく、なんかのトリガー的なことに使うと面白そう。