std::experimental::scope_exit
| ヘッダ <experimental/scope> で定義 |
||
| template< class EF > class scope_exit; |
(ライブラリ基本TS v3) | |
クラステンプレート scope_exit は、スコープから抜けるときに終了関数を呼び出すことを目的とした、汎用のスコープガードです。
scope_exit は CopyConstructible (コピー構築可能)、CopyAssignable (コピー代入可能)、MoveAssignable (ムーブ代入可能)ではありません。しかし、EF がいくつかの要件を満たす場合には MoveConstructible (ムーブ構築可能)であり、これにより scope_exit を別のオブジェクトにラップすることが許可されます。
scope_exit は、アクティブ(active)であるか、非アクティブ(inactive)であるかのどちらかです。アクティブな場合、破棄時に終了関数を呼び出します。非アクティブな場合、破棄時には何もしません。scope_exit は、終了関数から構築された後、アクティブな状態になります。
scope_exit は、手動または自動(ムーブコンストラクタによる)で release() を呼び出すことにより、非アクティブにすることができます。非アクティブな scope_exit は、別の非アクティブな scope_exit で初期化することでも得られます。一度 scope_exit が非アクティブになると、再びアクティブにすることはできません。
scope_exit は、実質的に EF と、アクティブかどうかを示す bool 型のフラグを保持します。
目次 |
[編集] テンプレートパラメータ
| EF | - | 格納される脱出関数の型 |
| 型要件 | ||
-EF は以下のいずれかでなければなりません。
| ||
| -std::remove_reference_t<EF> の左辺値を引数なしで呼び出すことは、適格でなければなりません。 | ||
[編集] メンバ関数
新しい scope_exit を構築する(公開メンバ関数) | |
scope_exit がアクティブな場合、スコープから抜けるときに終了関数を呼び出し、その後 scope_exit を破棄する(公開メンバ関数) | |
| operator= [削除] |
scope_exit は代入不可(public member function) |
変更 | |
scope_exit を非アクティブにする(公開メンバ関数) | |
[編集] 推論補助
[編集] ノート
動的記憶域期間を持つ scope_exit を構築すると、予期しない動作につながる可能性があります。
scope_exit オブジェクトに格納された EF が、それが定義された関数のローカル変数を(例えば、変数を参照でキャプチャするラムダとして)参照し、かつその変数がその関数で戻り値のオペランドとして使用される場合、scope_exit のデストラクタが実行されて終了関数を呼び出すときには、その変数はすでに返されている可能性があります。これは驚くような動作を引き起こすことがあります。
[編集] 例
#include <iostream> #include <cstdlib> #include <string_view> #include <experimental/scope> void print_exit_status(std::string_view name, bool exit_status, bool did_throw) { std::cout << name << ":\n"; std::cout << " Throwed exception " << (did_throw ? "yes" : "no") << "\n"; std::cout << " Exit status " << (exit_status ? "finished" : "pending") << "\n\n"; } // Randomly throw an exception (50% chance) void maybe_throw() { if (std::rand() >= RAND_MAX / 2) throw std::exception{}; } int main() { bool exit_status{false}, did_throw{false}; // Manual handling at "end of scope" try { maybe_throw(); exit_status = true; } catch (...) { did_throw = true; } print_exit_status("Manual handling", exit_status, did_throw); // Using scope_exit: runs on scope exit (success or exception) exit_status = did_throw = false; try { auto guard = std::experimental::scope_exit{[&]{ exit_status = true; } }; maybe_throw(); } catch (...) { did_throw = true; } print_exit_status("scope_exit", exit_status, did_throw); // Using scope_fail: runs only if an exception occurs exit_status = did_throw = false; try { auto guard = std::experimental::scope_fail{[&]{ exit_status = true; } }; maybe_throw(); } catch (...) { did_throw = true; } print_exit_status("scope_fail", exit_status, did_throw); // Using scope_success: runs only if no exception occurs exit_status = did_throw = false; try { auto guard = std::experimental::scope_success{[&]{ exit_status = true; } }; maybe_throw(); } catch (...) { did_throw = true; } print_exit_status("scope_success", exit_status, did_throw); }
出力
Manual handling: Throwed exception yes Exit status pending scope_exit: Throwed exception no Exit status finished scope_fail: Throwed exception yes Exit status finished scope_success: Throwed exception yes Exit status pending
[編集] 関連項目
| 関数オブジェクトをラップし、例外によってスコープを抜ける際にそれを呼び出す (クラステンプレート) | |
| 関数オブジェクトをラップし、正常にスコープを抜ける際にそれを呼び出す (クラステンプレート) | |
| (C++11) |
unique_ptr のためのデフォルトデリータ (クラステンプレート) |