scope_exitをmoveできるようにしたmovable_scope_exitを実装
scope_exitでは、その変数を定義したスコープを抜けたときの処理を記述できるように実装しましたが、抜けた時に処理をしないようにする、あるいは処理を延期できるようにすることを目標にmovable_scope_exitを実装しました。ポイントはAnyクラスの実装とほぼそっくりであることです。すなわち内部でポインタとしてtemplateの抽象クラスを保持し、必要なときにインターフェースとしてexecuteを呼び出す、というものです。キャプチャのラムダ式もオーバーヘッドなく使用できます。ただし仮想関数テーブル分および抽象クラス分のオーバーヘッドは避けられません。大したことはないと思いますが……。
使用例
{ movable_scope_exit mse; { auto se = make_movable_scope_exit( []() { printf("out\n"); }); mse = std::move(se); printf("1\n"); } printf("2\n"); } printf("3\n");
実行結果は、
1 2 out 3
実装例
class scope_exit_place_holder { public: virtual ~scope_exit_place_holder() { } virtual void execute() { } }; template <typename Func> class scope_exit_holder : public scope_exit_place_holder { public: scope_exit_holder(Func func) : func(func) { } virtual void execute() { func(); } Func func; }; class no_scope_exit { }; class movable_scope_exit { public: template <typename Func> movable_scope_exit(Func func) : func(std::make_unique<scope_exit_holder<Func>>(func)) { } movable_scope_exit(movable_scope_exit const& it) = delete; movable_scope_exit(movable_scope_exit&& it) : func(std::move(it.func)) {} movable_scope_exit(no_scope_exit const& it) : func(nullptr) {} movable_scope_exit() : func() { } movable_scope_exit& operator=(movable_scope_exit const& it) = delete; movable_scope_exit& operator=(no_scope_exit const& it) { func = nullptr; return *this; } movable_scope_exit& operator=(movable_scope_exit&& it) { func = std::move(it.func); return *this; } virtual ~movable_scope_exit() { if (func) { func->execute(); } } std::unique_ptr<scope_exit_place_holder> func; }; template <typename Func> static movable_scope_exit make_movable_scope_exit(Func func) { return movable_scope_exit(func); }