最終更新日時: 2024年06月11日 22時45分38秒 (JST)
Akira Takahashi が更新

履歴 編集

class
<ios>

# std::ios_base::failure

    namespace std {
      // C++03 まで
      class ios_base::failure : public exception {
      public:
        explicit failure(const string& msg);
        virtual ~failure();                         // 備考を参照
        virtual const char* what() const throw();
      };

      // C++11 から
      class ios_base::failure : public system_error {
      public:
        explicit failure(const string& msg, const error_code& ec = io_errc::stream);
        explicit failure(const char* msg, const error_code& ec = io_errc::stream);
      };
    }

## 概要

`ios_base::failure` は、ストリームライブラリ内の関数で、ストリームバッファ操作の間に検出したエラーを報告するために、例外として送出される全てのオブジェクトの型の基底クラスとして定義されている。
C++11 からは、エラー内容としてメッセージだけではなく、`error_code` を指定出来るようになった。
これによって、ストリームの操作で発生したエラーをプログラムから判別することが容易になる。
例えば、C++ 標準規格には、ストリームライブラリ内部で発生したエラーの `error_code` は `io_errc::stream` と `iostream_category()` で、OS レイヤで発生したエラーの `error_code` は `system_category()` で例外を送出するのが一般的だろうとの記載がある。
しかし、少なくとも現時点では `error_code` はあまり有効に機能していないようである。

## メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ |
`what` | エラーメッセージの取得 | C++03 まで

なお、一見 C++11 で `what()` が無くなっているように見えるが、`system_error::what()` を継承しているため、メンバ関数自体は使用可能である。

## 備考

- `ios_base::failure` は、C++11 から基底クラスが変更になっている。
  このため、C++03 まででも使用可能とするためには、基底クラスが `system_error` であることに依存しないようにする必要がある。
  なお、C++ 標準規格では、ライブラリの各クラスは基底クラスを直接継承しなくても（間接的に継承していれば）良いことになっている。
  このため、C++03 でも `exception` から直接派生していないかもしれないので、注意。
  （当然 C++11 でも `system_error` を直接継承していない可能性がある）
- C++03 まではデストラクタが宣言されていたが、例外指定が誤っていたため（基底クラス `exception` のデストラクタには `throw()` が付いているため、派生クラスにも `throw()` が必要）、C++11 では宣言自体が削除された。

## バージョン

## 言語

- C++98

### 処理系

- Clang: 3.0 ✅, 3.1 ✅, 3.2 ✅, 3.3 ✅, 3.4 ✅, 3.5.0 ✅, 3.6.0 ✅, 3.7.0 ✅, 3.8.0 ✅
- GCC: 4.3.6 ✅, 4.4.7 ✅, 4.5.4 ✅, 4.6.4 ✅, 4.7.3 ✅, 4.8.1 ✅, 4.8.2 ✅, 4.9.0 ✅, 4.9.1 ✅, 4.9.2 ✅, 5.1.0 ✅, 5.2.0 ✅, 6.0.0 ✅
- ICC: ??
- Visual C++: ??

### 備考

- GCC は 4.9.x までは C++11 モードでも `system_error` を継承していないので、注意が必要である。
- GCC 5.1.0 以降は現時点では `_GLIBCXX_USE_CXX11_ABI` マクロが `1` の場合（通常のビルドでは `1` がデフォルト）、C++03 モードでも C++11 モードでもライブラリ内から送出された例外を `ios_base::failure` 型では `catch` できない。
  `exception` 型であれば `catch` することができるが、いずれにせよストリーム系の例外とそれ以外の例外を区別することができなくなってしまう。
  したがって、少なくともこの問題が解決されるまでは、`_GLIBCXX_USE_CXX11_ABI` マクロを `0` にする他ないだろう。（C++03 モードにおける コンストラクタの事後条件の違いも参照）
  なお、`_GLIBCXX_USE_CXX11_ABI` マクロを `0` にしてしまうと、4.9.x までと同様、モードにかかわらず `system_error` を継承しなくなってしまうので、注意すること。
- Clang では、C++03 モードでも `strcmp(what(), msg.c_str()) == 0` にはならない。

## 参照

- `exception`
- `system_error`
- `io_errc`
- `iostream_category`
- N2769 Detailed Reporting for Input/Output Library Errors (Revision 2)
  基底クラスの変更を含む C++11 での提案文書
- DR331 bad declaration of destructor for ios_base::failure
  デストラクタ宣言削除の Defect Report
- Bug 66145 - [5/6 Regression] std::ios_base::failure objects thrown from libstdc++.so use old ABI
  GCC 5.1.0 以降でライブラリから送出された `ios_base::failure` が `catch` できない問題のバグレポート