Namespaces
Variants

noexcept specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Exceptions
try block
Throwing exceptions
Handling exceptions
Exception specification
noexcept specification (C++11)
dynamic specification ( until C++17* )
noexcept operator (C++11)

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

目次

構文

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

説明

noexcept指定子は関数型の一部ではなく( 動的例外指定 と同様)、関数、変数、関数型の非静的データメンバ、関数へのポインタ、関数への参照、またはメンバ関数へのポインタを宣言する際の lambda宣言子 またはトップレベルの 関数宣言子 の一部としてのみ現れます。また、関数へのポインタまたは参照であるパラメータや戻り値型の宣言でも使用できます。 typedef または 型エイリアス 宣言では使用できません。

void f() noexcept; // 関数f()は例外を投げない
void (*fp)() noexcept(false); // fpは例外を投げる可能性のある関数を指す
void g(void pfa() noexcept);  // gは例外を投げない関数へのポインタを受け取る
// typedef int (*pf)() noexcept; // エラー
(C++17まで)

noexcept指定子は関数型の一部であり、あらゆる 関数宣言子 の一部として現れることができます。

(C++17以降)

C++のすべての関数は、 non-throwing または potentially throwing のいずれかです:

  • potentially-throwing 関数は以下の通りです:
(C++17まで)
  • noexcept 指定子で宣言され、その false と評価される関数
  • noexcept 指定子なしで宣言された関数(以下を除く)
  • コンストラクタの暗黙的な定義が呼び出す基底クラスまたはメンバーのコンストラクタが 例外を投げる可能性がある 場合(下記参照)
  • そのような初期化の部分式(デフォルト引数式など)が 例外を投げる可能性がある 場合(下記参照)
  • デフォルトメンバ初期化子(デフォルトコンストラクタのみ)が 例外を投げる可能性がある 場合(下記参照)
  • コピー代入演算子 ムーブ代入演算子 (暗黙的に宣言されたもの、または最初の宣言でデフォルト化されたもの)ただし、暗黙的な定義内のいずれかの代入演算子の呼び出しが 例外を投げる可能性がある 場合を除く(下記参照)
  • 比較演算子 が最初の宣言でdefault指定されている場合、ただし暗黙的な定義内でのいずれかの比較演算子の呼び出しが 例外送出の可能性がある 場合を除く(下記参照)
(C++20以降)
  • noexcept指定子の expression true と評価される関数、およびデストラクタ、デフォルト化された特殊メンバ関数、解放関数を含むその他すべての関数は非スロー関数です

Explicit instantiations は noexcept 指定子を使用してもよいが、必須ではない。使用する場合、例外指定は他のすべての宣言と同じでなければならない。診断メッセージは、単一の翻訳単位内で例外指定が同じでない場合にのみ要求される。

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

void f() noexcept;
void f(); // エラー: 異なる例外仕様
void g() noexcept(false);
void g(); // OK、gの両宣言は潜在的に例外を送出する可能性がある

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

注意点: - HTMLタグと属性はそのまま保持 - C++固有の用語("pointers", "member function", "non-throwing functions", "potentially-throwing functions"など)は翻訳せず - 技術的な正確性と専門性を維持 - 日本語として自然な表現になるよう調整
void ft(); // 例外を投げる可能性あり
void (*fn)() noexcept = ft; // エラー

仮想関数が非スローである場合、オーバーライドを削除定義した場合を除き、すべてのオーバーライダの宣言(定義を含む)も同様に非スローでなければなりません:

struct B
{
    virtual void f() noexcept;
    virtual void g();
    virtual void h() noexcept = delete;
};
struct D: B
{
    void f();          // 不正: D::fは例外を投げる可能性があるが、B::fは非投げる
    void g() noexcept; // OK
    void h() = delete; // OK
};

例外を投げない関数は、例外を投げる可能性のある関数を呼び出すことが許可されています。例外が投げられ、ハンドラの検索が例外を投げない関数の最も外側のブロックに到達した場合、関数 std::terminate が呼び出されます:

extern void f(); // 例外を投げる可能性あり
void g() noexcept
{
    f();      // fが例外を投げる場合でも有効
    throw 42; // 有効、事実上std::terminateの呼び出し
}

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

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

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

関数のnoexcept指定子は、以下の文脈において 必要 と見なされます:

  • 式内で、オーバーロード解決によって関数が選択される場合
  • 関数が ODR-use される場合
  • 関数はODR-useされるはずだが、未評価オペランド内に現れる場合
template<class T>
T f() noexcept(sizeof(T) < 4);
int main()
{
    decltype(f<void>()) *p; // fは評価されないが、noexcept指定子は必要
                            // noexcept指定子のインスタンス化時に
                            // sizeof(void)の計算が行われるためエラー
}
  • この仕様は、別の関数宣言(例えば、仮想関数のオーバーライドや関数テンプレートの明示的特殊化)と比較するために必要です。
  • 関数定義内で
  • デフォルト化された特殊メンバ関数が自身の例外仕様を決定するためにこれをチェックする必要があるため、仕様が必要です(これは、デフォルト化された特殊メンバ関数の仕様自体が必要とされる場合にのみ発生します)。

potentially-throwing expression の形式的定義 (前述の通り、デストラクタ、コンストラクタ、および代入演算子のデフォルト例外仕様を決定するために使用されます):

e potentially-throwing である条件は以下の通り:

  • e は、関数、関数へのポインタ、またはメンバ関数へのポインタに対する関数呼び出しであり、 例外送出の可能性がある 場合 (ただし、 e コア定数式 である場合は除く (C++17まで)
  • e 例外送出の可能性がある 関数への暗黙的な呼び出しを行う場合(オーバーロードされた演算子、 new -式内のアロケート関数、関数引数のコンストラクタ、または e が完全式である場合のデストラクタなど)
  • e throw である場合
  • 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; // 暗黙の例外仕様は 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() は new 演算子により例外を投げる可能性あり
    // D::D(const D&) は例外を投げない
    // D::D(D&&) は例外を投げる可能性あり:Bのコンストラクタのデフォルト引数が例外を投げる可能性があるため
    // D::~D() は例外を投げる可能性あり
    // 注記:もし A::~A() が仮想関数だった場合、例外を投げない仮想関数のオーバーライドは
    // 例外を投げる可能性がある関数にできないため、このプログラムは不適格となる
};

注記

定数 expression の用途の一つは( noexcept operator と共に)特定の型に対しては noexcept を宣言し、他の型に対しては宣言しない関数テンプレートを定義することです。

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

非推奨化

noexcept throw ( ) の改良版であり、C++11で非推奨となりました。C++17以前の throw ( ) とは異なり、 noexcept std::unexpected を呼び出さず、スタックの巻き戻しを行うかどうかは不定であり、 std::terminate を呼び出します。これにより、コンパイラは noexcept throw ( ) の実行時オーバーヘッドなしに実装できる可能性があります。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 に続く ( が初期化子を開始する可能性があった 例外指定の一部でのみ
使用可能
CWG 2039 C++11 変換前の式のみが定数であることが要求されていた 変換も定数式で有効で
なければならない

関連項目

noexcept operator (C++11) 式が例外をスローするかどうかを判定する
Dynamic exception specification (until C++17) 関数がスローする例外を指定する (C++11で非推奨)
throw expression エラーを通知し、制御をエラーハンドラに転送する
ムーブコンストラクタが例外をスローしない場合、引数をxvalueに変換する
(関数テンプレート)