Scope Guard

Scope Guard

3通りほど方法がある(と思う)けど,どれがいいのか?

方策1

作れそうな気がしてScope Guardを作ってみたけど,
どっかで見たことあるなーと思ってたら案の定ここで読んだものでした. >http://d.hatena.ne.jp/faith_and_brave/20081212
これが普通のやり方. Boost(のdetail)に入ってるみたいだし.*1

 // 推論した型Fを実装クラスの基底クラスに持っておき,
 // デストラクタでダウンキャストしてFを評価する.
 template<typename F> scope_guard::scope_guard(F f)
     : f_(new impl<F>(f))
 {}
方策2

shared_ptrのデストラクタ指定を使う.

using namespace std;
void End(string const & msg){
  cout << "End call" << msg << endl;
}

int main(){
  string msg("guard message");
  boost::shared_ptr<void> guard(static_cast<void*>(0), boost::bind(End, msg));

  cout << "main end" << endl;

  return (0);
}
// > main end
// > End call guard message    <- デストラクタで実行されるので後ろに来る

scoped_ptrが使えるならそちらの方が望ましいかも知れないけど,
重くしたくないのか,デストラクタが指定できない.

方策3

BOOST_SCOPED_EXITを使う.

bool atomic_behavior(){
  std::string msg(" スコープ終了のお知らせ ");
  int x = 777;
  char cs[10];
  bool ret=true;

  commit(msg, x);

  // コンマで区切らないで環境を渡す
  BOOST_SCOPE_EXIT( (&msg) (x) (&cs) ){ // 配列は'&'を付けるとキャプチャ出来る.
    if( isError() ){
      rollback();
      ret=false;
    }
    std::cout << msg << std::endl;
  } BOOST_SCOPE_EXIT_END

  /*
      ここで他の処理
  */

  // scope_exit発動

  return (ret);
}

boostの黒魔術だけどすごく便利 :)

まとめ
  1. 終了処理が関数オブジェクトになっている場合は,scope_guardを使う.
  2. 必要になった場所で,複雑なラムダ式は書く自身がないので, ^^;;まともな終了処理が必要ならBOOST_SCOPE_EXITを使う.
  3. 一目で分かるような簡単な処理ならshared_ptrにラムダ式を渡す.


c++0xならラムダ式があるので,shared_ptrにラムダ式を渡すのが楽だと思う.
あるいはBOOST_SCOPE_EXITがもっと自然に記述できるはずだが,ちょっと無理してる感じ.
言語に取り込まれてもいいような気もする.