動的例外指定
関数が直接または間接的に投げる可能性のある例外の一覧を指定します。
構文
throw( )
|
(1) | (C++11で非推奨)(C++20で削除) | |||||||
throw(typeid, typeid, ...)
|
(2) | (C++11で非推奨)(C++17で削除) | |||||||
|
1) 例外を投げない動的例外指定。
|
(C++17未満) |
|
1) noexcept(true) と同じです。
|
(C++17以上) |
この指定はラムダ宣言子に対して、または型が関数型、関数へのポインタ型、関数への参照型、メンバ関数へのポインタ型である関数、変数、または非静的データメンバのトップレベルの (C++17未満)宣言子である関数宣言に対してのみ使用できます。 引数の宣言子または戻り値の型の宣言子に対しても使用できます。
void f() throw(int); // OK、関数の宣言。
void (*pf)() throw (int); // OK、関数へのポインタの宣言。
void g(void pfa() throw(int)); // OK、関数へのポインタである引数の宣言。
typedef int (*pf)() throw(int); // エラー、 typedef 宣言。
説明
関数がその例外指定の中に型 T を指定して宣言されているとき、その関数はその型またはその型から派生した型の例外を投げる可能性があります。
不完全型、 cv void* 以外の不完全型へのポインタまたは参照、および右辺値参照型は、例外指定に指定できません。 配列および関数型は (もし指定された場合) 対応するポインタ型に調節されます。 パラメータパックも使用できます。 (C++11以上)
関数がその例外指定に記載されていない型の例外を投げた場合は、関数 std::unexpected が呼ばれます。 デフォルトでは std::terminate を呼びますが、 (std::set_unexpected を介して) ユーザ定義の関数に置き換えることができ、 std::terminate を呼ぶまたは例外を投げることができます。 std::unexpected から投げられた例外が例外指定によって受理される場合は、スタックの巻き戻しが通常通りに続けられます。 そうでなく、 std::bad_exception が例外指定によって受理される場合は、 std::bad_exception が投げられます。 そうでなければ、 std::terminate が呼ばれます。
潜在的な例外関数 2) そうでなく、
f、 pf または pmf の宣言が動的例外指定(非推奨)を用いている場合、集合はその指定されている型から構成されます。3) そうでなければ、集合はすべての型の集合です。
ノート: 暗黙に宣言された特別なメンバ関数 (コンストラクタ、代入演算子、およびデストラクタ) および継承コンストラクタについては、潜在的な例外の集合はそれらが呼び出すであろうすべてのもの (非変種非静的データメンバ、直接の基底、および (適切であれば) 仮想基底のコンストラクタ、代入演算子、デストラクタ (いつも通りデフォルト引数式を含みます)) の潜在的な例外の集合を合わせたものです。 式 1)
e が関数呼び出し式の場合、
2)
e が暗黙に関数を呼ぶ (それが演算子式であって演算子がオーバーロードされている、それが new 式であって確保関数がオーバーロードされている、またはそれが完全式であって一時オブジェクトのデストラクタが呼ばれる) 場合、集合はその関数の集合です。void f() throw(int); // f() の集合は int です。
void g(); // g() の集合はすべての型の集合です。
struct A { A(); }; // new A の集合はすべての型の集合です。
struct B { B() noexcept; }; // B() の集合は空です。
struct D() { D() throw (double); }; // new D の集合はすべての型の集合です。
すべての暗黙に宣言されたメンバ変数 (および継承コンストラクタ) は以下のように選択された例外指定を持ちます。
struct A {
A(int = (A(5), 0)) noexcept;
A(const A&) throw();
A(A&&) throw();
~A() throw(X);
};
struct B {
B() throw();
B(const B&) = default; // 例外指定は「noexcept(true)」です。
B(B&&, int = (throw Y(), 0)) noexcept;
~B() throw(Y);
};
int n = 7;
struct D : public A, public B {
int * p = new (std::nothrow) int[n];
// D は暗黙に宣言された以下のメンバを持ちます。
// D::D() throw(X, std::bad_array_new_length);
// D::D(const D&) noexcept(true);
// D::D(D&&) throw(Y);
// D::~D() throw(X, Y);
};
|
(C++17以上) |
例
#include <iostream>
#include <exception>
#include <cstdlib>
class X {};
class Y {};
class Z : public X {};
class W {};
void f() throw(X, Y)
{
int n = 0;
if (n) throw X(); // OK。
if (n) throw Z(); // これも OK。
throw W(); // std::unexpected() を呼びます。
}
int main() {
std::set_unexpected([]{
std::cout << "That was unexpected" << std::endl; // フラッシュは必要です。
std::abort();
});
f();
}
出力:
That was unexpected