名前空間
変種
操作

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

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

関数が例外を投げ得るかどうかを指定します。

目次

[編集] 構文

noexcept (1)
noexcept(expression) (2)
throw() (3) (非推奨)(C++20で削除)
1) noexcept ( true ) と同じです。
2) expressiontrue に評価される場合、関数はいかなる例外も投げないと宣言されます。
3) noexcept(true) と同じです。
(C++17以上)
(C++20未満)
3) 例外を投げない動的例外指定 (noexcept(true) と異なり、スタックの巻き戻しを保証し、 std::unexpected を呼ぶ可能性があります)。
(C++17未満)
expression - bool 型の文脈的に変換された定数式

[編集] 説明

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

(C++17以上)

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

void f() noexcept; // 関数 f() は例外を投げません。
void (*fp)() noexcept(false); // fp は例外を投げるかもしれない関数を指します。
void g(void pfa() noexcept);  // g は例外を投げない関数へのポインタを受け取ります。
// typedef int (*pf)() noexcept; // エラー。
(C++17未満)

C++ のすべての関数は例外を投げない潜在的に例外を投げるかのいずれかです。

  • 潜在的に例外を投げる関数は以下のいずれかです。
(C++17未満)
  • expressionfalse に評価される noexcept 指定子付きで宣言された関数。
  • noexcept 指定子なしで宣言された関数。 ただし以下を除きます。
  • コンストラクタの暗黙の定義が呼ぶ基底またはメンバに対するコンストラクタが潜在的に例外を投げる (後述)。
  • 初期化の部分式 (デフォルト引数式など) が潜在的に例外を投げる (後述)。
  • デフォルトメンバ初期化子 (デフォルトコンストラクタの場合のみ) が潜在的に例外を投げる (後述)。
  • 最初の宣言においてデフォルト化されたコピー代入演算子、ムーブ代入演算子。 ただし暗黙の宣言において何らかの代入演算子の呼び出しが潜在的に例外を投げる (後述) 場合は除きます。
  • 解放関数
  • 例外を投げない関数はそれ以外の全部です (expressiontrue に評価される noexcept 指定子付きの関数、デストラクタ、デフォルト化された特別なメンバ関数および解放関数)。

明示的実体化は noexcept 指定子を使用しても構いません (が要求はされません)。 使用する場合、例外指定は他のすべての宣言に対するものと同じでなければなりません。 診断は例外指定が単一翻訳単位内で同じでない場合にのみ要求されます。

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

void f() noexcept;
void f(); // エラー、例外指定が異なります。
void g() noexcept(false);
void g(); // OK、 g に対する両方の宣言が潜在的に例外を投げます。

例外を投げない関数へのポインタは潜在的に例外を投げる関数へのポインタに暗黙に変換可能 (C++17以上)代入可能 (C++17未満)ですが、その逆はできません。

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();              // ill-formed、 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 指定は、関数宣言と一緒には実体化されません。 必要なとき (下で定義される通り) にのみ実体化されます。

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

関数テンプレートの特殊化の noexcept 指定が必要だけれどもまだ実体化されていない場合は、依存名が名前探索され、その特殊化の宣言に対するかのように、 expression で使用されるあらゆるテンプレートが実体化されます。

関数の noexcept 指定は、以下の文脈において、必要であるとみなされます。

  • 式内で、関数がオーバーロード解決によって選択された場合。
  • 関数が ODR 使用された。
  • 関数が ODR 使用されたであろうけれども未評価被演算子内で現れた。
template<class T> T f() noexcept(sizeof(T) < 4);
int main() {
    decltype(f<void>()) *p; // f は未評価ですが、 noexcept 指定は必要です。
                            // noexcept 指定の実体化は sizeof(void) を計算するため
                            // エラーです。
}
  • 指定は別の関数の宣言と比較するために必要です (例えば仮想関数のオーバーライドにおいて、または関数テンプレートの明示的特殊化において)。
  • 関数定義内で。
  • 指定はデフォルト化された特別なメンバ関数がそれ自身の例外指定を決定するためにチェックする必要があるために必要です (これはそのデフォルト化された特別なメンバ関数それ自身の指定が必要であるときにのみ行われます)。
(C++14以上)

潜在的に例外を投げる関数の形式的な定義は以下の通りです (上で説明した通り、デストラクタ、コンストラクタおよび代入演算子のデフォルトの例外指定を決定するために使用されます)。

動的例外指定を参照してください。

(C++17未満)

以下の場合、式 e潜在的に例外を投げます

  • e潜在的に例外を投げる関数または関数へのポインタの関数呼び出しである。
  • e潜在的に例外を投げる関数の暗黙の呼び出しである (オーバーロード演算子、 new 式における確保関数、関数引数に対するコンストラクタ、 e が完全式の場合のデストラクタなど)。
  • ethrow 式である。
  • 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() が仮想であったならば、例外を投げない仮想関数のオーバーライドは
  // 潜在的に例外を投げるであれないため、プログラムは ill-formed であったでしょう。
};
(C++17以上)

[編集] ノート

定数式 expression の使用方法のひとつは (noexcept 演算子と共に) 何らかの型に対しては noexcept を宣言するけれどもそれ以外に対してはそうでない関数テンプレートを定義することです。

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

[編集] 非推奨

noexcept は、 C++11 で非推奨になったthrow() の、改善版です。 C++17 未満の throw() と異なり、 noexceptstd::unexpectedを呼ばず、スタックを巻き戻すかもしれないし巻き戻さないかもしれません (これはコンパイラが throw() の実行時オーバーヘッドなしに noexcept を実装することを潜在的に可能にします)。 C++17 以降、 throw()noexcept(true) と正確に同等であると再定義されました。

[編集] 欠陥報告

以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。

DR 適用先 発行時の動作 正しい動作
CWG 2039 C++11 only the expression before conversion is required to be constant the conversion must also be valid in a constant expression

[編集] キーワード

noexcept

[編集]

// foo が noexcept 宣言されるかどうかは、
// 式 T() が何らかの例外を投げるかどうかによります。
template <class T>
  void foo() noexcept(noexcept(T())) {}
 
void bar() noexcept(true) {}
void baz() noexcept { throw 42; }  // noexcept は noexcept(true) と同じです。
 
int main() 
{
    foo<int>();  // noexcept(noexcept(int())) → noexcept(true) のため、これは OK です。
 
    bar();  // OK
    baz();  // コンパイルできますが、実行時に std::terminate を呼びます。
}


[編集] 関連項目

noexcept 演算子 式が何らかの例外を投げるかどうか調べます (C++11以上) [edit]
例外指定 何の例外が関数によって投げられるかを指定します (非推奨) [edit]
throw 式 エラーを通知し、制御をエラーハンドラに移します[edit]
ムーブコンストラクタが例外を投げない場合、右辺値参照を取得します
(関数テンプレート) [edit]