名前空間
変種
操作

noexcept 指定子 (C++11 以降)

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept 指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
例外
tryブロック
例外を送出する
例外を処理する
例外仕様
    noexcept 仕様 (C++11)
    動的例外指定 (C++17* まで)
noexcept 演算子 (C++11)
 

関数が例外をスローするかどうかを指定します。

目次

[編集] 構文

noexcept (1)
noexcept() (2)
throw() (3) (C++17で非推奨)
(C++20で削除)
1) noexcept(true) と同じ
2) true に評価される場合、関数はいかなる例外もスローしないと宣言されます。noexcept に続く ( は常にこの形式の一部です(初期化子を開始することはありません)。
3) noexcept(true) と同じ (C++17 以前のセマンティクスについては動的例外指定を参照)
- bool の文脈的に変換された定数式

[編集] 説明

noexcept-specification は関数の型の一部ではなく (動的例外指定と同様)、関数、変数、関数型の非静的データメンバー、関数へのポインタ、関数への参照、またはメンバー関数へのポインタを宣言する際のラムダ宣言子またはトップレベルの関数宣言子の一部としてのみ現れることができます。また、それらの宣言のいずれかで、結果的に関数へのポインタまたは参照となるパラメータまたは戻り値を宣言する場合にも現れることができます。typedef または型エイリアス宣言には現れることはできません。

void f() noexcept; // the function f() does not throw
void (*fp)() noexcept(false); // fp points to a function that may throw
void g(void pfa() noexcept);  // g takes a pointer to function that doesn't throw
// typedef int (*pf)() noexcept; // error
(C++17まで)

noexcept-specification は関数の型の一部であり、任意の関数宣言子の一部として現れることがあります。

(C++17以降)

C++ のすべての関数は、非スローであるか、潜在的にスローであるかのどちらかです。

  • 潜在的にスローする関数は次のとおりです。
(C++17まで)
  • false に評価される noexcept 指定子で宣言された関数
  • 以下のものを除く、noexcept 指定子なしで宣言された関数
  • コンストラクタの暗黙の定義が呼び出す基底またはメンバーのコンストラクタが潜在的にスローである場合 (下記参照)
  • デフォルト引数式など、そのような初期化の副式が潜在的にスローである場合 (下記参照)
  • デフォルトメンバ初期化子 (デフォルトコンストラクタの場合のみ) が潜在的にスローである場合 (下記参照)
  • コピー代入演算子、ムーブ代入演算子が暗黙的に宣言されるか、最初の宣言でデフォルト指定された場合。ただし、暗黙の定義におけるいずれかの代入演算子の呼び出しが潜在的にスローである場合を除く (下記参照)
  • 比較演算子が最初の宣言でデフォルト指定された場合。ただし、暗黙の定義におけるいずれかの比較演算子の呼び出しが潜在的にスローである場合を除く (下記参照)
(C++20以降)
  • 非スロー関数とは、その他のすべての関数です (noexcept 指定子のtrue に評価される関数、デストラクタ、デフォルト化された特殊メンバ関数、およびデアロケーション関数など)。

明示的なインスタンス化では noexcept 指定子を使用できますが、必須ではありません。使用する場合、例外指定は他のすべての宣言と同じでなければなりません。単一の翻訳単位内で例外指定が同じでない場合にのみ診断が必須となります。

例外指定のみが異なる関数はオーバーロードできません (戻り値の型と同様に、例外指定は関数型の一部ですが、関数シグネチャの一部ではありません)(C++17 以降)

void f() noexcept;
void f(); // error: different exception specification
void g() noexcept(false);
void g(); // ok, both declarations for g are potentially-throwing

非スロー関数へのポインタ (メンバー関数へのポインタを含む) は、潜在的にスローする関数へのポインタに 代入または初期化に使用できますが(C++17 まで) 暗黙的に変換可能ですが(C++17 以降)、その逆はできません。

void ft(); // potentially-throwing
void (*fn)() noexcept = ft; // error

仮想関数が非スローである場合、すべてのオーバーライダのすべての宣言(定義を含む)も、そのオーバーライダが削除済みとして定義されていない限り、非スローでなければなりません。

struct B
{
    virtual void f() noexcept;
    virtual void g();
    virtual void h() noexcept = delete;
};
 
struct D: B
{
    void f();          // ill-formed: D::f is potentially-throwing, B::f is non-throwing
    void g() noexcept; // OK
    void h() = delete; // OK
};

非スロー関数は、潜在的にスローする関数を呼び出すことが許可されています。例外がスローされ、ハンドラの検索が非スロー関数の最外ブロックに到達すると、関数std::terminateが呼び出されます。

extern void f(); // potentially-throwing
 
void g() noexcept
{
    f();      // valid, even if f throws
    throw 42; // valid, effectively a call to std::terminate
}

関数テンプレート特殊化の例外指定は、関数宣言と共にインスタンス化されません。それは(下記で定義されるように)必要な場合にのみインスタンス化されます。

暗黙的に宣言された特殊メンバ関数の例外指定も、必要になったときにのみ評価されます(特に、派生クラスのメンバ関数の暗黙的宣言は、基底メンバ関数の例外指定のインスタンス化を必要としません)。

関数テンプレートの特殊化の noexcept-specification が必要であるが、まだインスタンス化されていない場合、依存名は検索され、で使用されているすべてのテンプレートは、特殊化の宣言の場合と同様にインスタンス化されます。

関数の noexcept-specification は、以下のコンテキストで必要とみなされます。

  • オーバーロード解決によって関数が選択される式において
  • 関数がodr-usedされる場合
  • 関数が odr-used されるはずだが、未評価のオペランドに現れる場合
template<class T>
T f() noexcept(sizeof(T) < 4);
 
int main()
{
    decltype(f<void>()) *p; // f unevaluated, but noexcept-spec is needed
                            // error because instantiation of the noexcept specification 
                            // calculates sizeof(void)
}
  • 別の関数宣言と比較するために指定が必要な場合 (例: 仮想関数のオーバーライダや関数テンプレートの明示的な特殊化)
  • 関数定義において
  • デフォルト化された特殊メンバ関数が自身の例外指定を決定するためにそれをチェックする必要があるため、指定が必要な場合 (これは、デフォルト化された特殊メンバ関数自体の指定が必要な場合にのみ発生します)。

潜在的にスローする式の正式な定義(上記のようにデストラクタ、コンストラクタ、代入演算子のデフォルト例外指定を決定するために使用されます)

e潜在的にスローであるのは、以下のいずれかの条件を満たす場合です。

  • e が、潜在的にスローする関数、関数へのポインタ、またはメンバ関数へのポインタの関数呼び出しである場合。ただし、eコア定数式である場合を除く(C++17 まで)
  • e潜在的にスローする関数への暗黙の呼び出しを行う場合 (オーバーロードされた演算子、new-expression のアロケーション関数、関数引数のコンストラクタ、または e が完全式の場合はデストラクタなど)
  • ethrow-expressionである場合
  • e が多態的な参照型をキャストするdynamic_castである場合
  • e が多態的な型への参照解除されたポインタに適用されるtypeid式である場合
  • e が潜在的にスローする直接の副式を持つ場合
struct A
{
    A(int = (A(5), 0)) noexcept;
    A(const A&) noexcept;
    A(A&&) noexcept;
    ~A();
};
 
struct B
{
    B() throw();
    B(const B&) = default; // implicit exception specification is noexcept(true)
    B(B&&, int = (throw Y(), 0)) noexcept;
    ~B() noexcept(false);
};
 
int n = 7;
struct D : public A, public B
{
    int * p = new int[n];
    // D::D() potentially-throwing because of the new operator
    // D::D(const D&) non-throwing
    // D::D(D&&) potentially-throwing: the default argument for B’s constructor may throw
    // D::~D() potentially-throwing
 
    // note; if A::~A() were virtual, this program would be ill-formed because an overrider
    // of a non-throwing virtual cannot be potentially-throwing
};

[編集] ノート

定数の使用法の1つは、(noexcept 演算子と共に) 一部の型には noexcept を宣言し、他の型には宣言しない関数テンプレートを定義することです。

関数に対する noexcept 指定はコンパイル時のチェックではないことに注意してください。これは単に、関数が例外をスローするかどうかをプログラマーがコンパイラに通知する方法です。コンパイラはこの情報を使用して、非スロー関数に対する特定の最適化を有効にしたり、特定の式が例外をスローすると宣言されているかどうかをコンパイル時にチェックできるnoexcept 演算子を有効にしたりすることができます。たとえば、std::vector などのコンテナは、要素のムーブコンストラクタが noexcept であれば要素をムーブし、そうでなければコピーします (ただし、コピーコンストラクタがアクセス不可能で、潜在的にスローするムーブコンストラクタがアクセス可能な場合は、強力な例外保証は放棄されます)。

[編集] 非推奨

noexcept は C++11 で非推奨となったthrow()の改良版です。C++17 以前のthrow()とは異なり、noexceptstd::unexpectedを呼び出さず、スタックをアンワインドするかどうかは不定であり、std::terminateを呼び出します。これにより、コンパイラはthrow()の実行時オーバーヘッドなしでnoexceptを実装できる可能性があります。C++17以降、throw()noexcept(true)と完全に同等であると再定義されています。

機能テストマクロ 規格 機能
__cpp_noexcept_function_type 201510L (C++17) 例外指定を型システムの一部にする

[編集] キーワード

noexcept, throw(C++17 以降)(C++20 まで)

[編集]

// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions
template<class T>
void foo() noexcept(noexcept(T())) {}
 
void bar() noexcept(true) {}
void baz() noexcept { throw 42; } // noexcept is the same as noexcept(true)
 
int main() 
{
    foo<int>(); // noexcept(noexcept(int())) => noexcept(true), so this is fine
 
    bar(); // fine
    baz(); // compiles, but at runtime this calls std::terminate
}

[編集] 欠陥レポート

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 1330 C++11 例外指定が熱心にインスタンス化される可能性がある 必要に応じてのみインスタンス化される
CWG 1740 C++11 (noexcept の後に初期化子を開始する可能性がある それの一部にしかありえない
noexcept指定
CWG 2039 C++11 変換前の式のみが定数である必要がある 変換も定数式で有効でなければならない
定数式で有効

[編集] 関連項目

noexcept 演算子(C++11) 式が例外をスローするかどうかを決定する[編集]
動的例外指定(C++17 まで) 関数がスローする例外を指定する (C++11 で非推奨) [編集]
throw エラーを通知し、エラーハンドラに制御を転送する[編集]
ムーブコンストラクタが例外を投げない場合に引数をxvalueに変換する
(関数テンプレート) [編集]
English 日本語 中文(简体) 中文(繁體)