標準ライブラリにおける noexcept 指定の方針(メモ)

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf

にて、 C++0x の標準ライブラリにおける noexcept 指定の基準が示されたので、以下 適当に和訳。

  • デストラクタには例外指定を付けない。
    • その結果として、暗黙に指定された(例外を投げない)例外指定が使用される。
  • 広い契約 ( Wide Contract ) を持った関数が、どのような状況であっても例外を投げない場合、条件式のない noexcept 指定をつける。
  • swap 関数、ムーブコンストラクタ、ムーブ代入演算子が、条件付きで広い契約を持つ場合には、条件式を伴った noexcept 指定を付ける。 それ以外の関数に対しては、条件式を伴った noexcept 指定は行わない。
  • C との互換性の為に用意された関数には、条件式のない noexcept 指定がされていてもよい。

ある関数が「広い契約を持つ」とは、その関数が どのような状況で呼ばれたとしても、決して未定義動作が起きない、ということ。
例えば std::vector::begin()std::vector::at( size_type ) は広い契約を持つ。 このうち、前者は例外を投げることが無いため、条件式のない noexcept によって例外指定が行われる。 後者は範囲外アクセスの際に例外を投げるので、 noexcept による例外指定は行われない。
一方で std::vector::front()std::vector::operator[]( size_type ) は、広い契約を持たない。 前者は空の場合に、後者は範囲外アクセスの場合に、それぞれ未定義動作となるためだ。 これらの関数に対して noexcept 指定は行われない。

// なお、未定義動作が起こり得る際に noexcept を排除するのは、デバッグ用の都合。
// これにより、未定義動作が起こった場合には例外を投げる、という処理が可能になる。
// ムーブ時に条件付き noexcept を許可するのは、ムーブに関しては
// 「例外が投げられる可能性の有無によって処理を切り替える」ケースが多いため。
// ムーブ時以外に条件付き noexcept を排除しているのは、規格の不必要な複雑化を避けるためだろう。
// 個人的には、コンストラクタや代入演算子に関しては、ムーブに限らず、条件付き noexcept 指定が有ってもいいと思うが…。