std::experimental::scope_success
| ヘッダ <experimental/scope> で定義 |
||
| template< class EF > class scope_success; |
(ライブラリ基本TS v3) | |
クラステンプレート scope_success は、スコープが正常に終了したときに脱出関数を呼び出すことを目的とした、汎用のスコープガードです。
scope_success はコピー構築可能 (CopyConstructible)、コピー代入可能 (CopyAssignable)、またはムーブ代入可能 (MoveAssignable)ではありませんが、EFが特定の要件を満たす場合にはムーブ構築可能 (MoveConstructible)にすることができます。これにより、scope_success を別のオブジェクトにラップすることが許可されます。
scope_success はアクティブ (active) または非アクティブ (inactive) のいずれかの状態になります。アクティブな場合、破棄時に脱出関数を呼び出します。非アクティブな場合、破棄時には何もしません。scope_success は脱出関数から構築された後、アクティブな状態になります。
scope_success は、手動または自動(ムーブコンストラクタによる)で release() を呼び出すことにより非アクティブにすることができます。非アクティブな scope_success は、別の非アクティブな scope_success で初期化することでも得られます。一度非アクティブになると、再びアクティブになることはできません。
scope_success は実質的に EF と、アクティブかどうかを示す bool 型のフラグを保持します。それに加えて、デストラクタがスタック巻き戻し中に呼び出されたかどうかを検出するために使用される、未捕捉の例外のカウンタも保持します。
目次 |
[編集] テンプレートパラメータ
| EF | - | 格納される脱出関数の型 |
| 型要件 | ||
-EF は以下のいずれかでなければなりません。
| ||
| -std::remove_reference_t<EF> の左辺値を引数なしで呼び出すことは、適格でなければなりません。 | ||
[編集] メンバ関数
新しい scope_success を構築します(公開メンバ関数) | |
scope_success がアクティブな場合、スコープが正常に終了するときに脱出関数を呼び出し、その後 scope_success を破棄します(公開メンバ関数) | |
| operator= [削除] |
scope_success は代入できません(public member function) |
変更 | |
scope_success を非アクティブにします(公開メンバ関数) | |
[編集] 推論補助
[編集] ノート
動的記憶域期間を持つ scope_success を構築すると、予期しない振る舞いを引き起こす可能性があります。
異なるスレッドで作成された別の scope_success から scope_success を構築することも、予期しない振る舞いを引き起こす可能性があります。なぜなら、破棄時に異なるスレッドで取得された未捕捉の例外の数が比較される可能性があるためです。
scope_success オブジェクトに格納された EF が、それが定義された関数のローカル変数を(例えば、ラムダが参照で変数をキャプチャするように)参照しており、その変数がその関数で戻り値のオペランドとして使用される場合、scope_success のデストラクタが脱出関数を呼び出して実行されるときには、その変数はすでに返されている可能性があります。これは驚くような振る舞いを引き起こす可能性があります。
[編集] 例
#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 のためのデフォルトデリータ (クラステンプレート) |