C++ では例外指定子を使用する必要がありますか? 質問する

C++ では例外指定子を使用する必要がありますか? 質問する

C++ では、例外指定子を使用して、関数が例外をスローするかどうかを指定できます。例:

void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type

以下の理由から、実際に使用するかどうかは疑問です。

  1. コンパイラは例外指定子を厳密に強制するわけではないので、メリットは大きくありません。理想的には、コンパイル エラーが発生するようにします。
  2. 関数が例外指定子に違反した場合、標準的な動作はプログラムを終了することだと思います。
  3. VS.Net では、throw(X) は throw(...) として扱われるため、標準への準拠は強くありません。

例外指定子を使用する必要があると思いますか?
「はい」または「いいえ」で回答し、回答を正当化する理由をいくつか示してください。

ベストアンサー1

いいえ。

その理由の例をいくつか挙げます。

  1. テンプレートコードは例外仕様で記述することは不可能です。

    template<class T>
    void f( T k )
    {
         T x( k );
         x.x();
    }
    

    コピーによって例外がスローされる可能性があり、パラメータの受け渡しによって例外がスローされる可能性があり、さらにx()不明な例外がスローされる可能性もあります。

  2. 例外仕様は拡張性を妨げる傾向があります。

    virtual void open() throw( FileNotFound );
    

    進化するかもしれない

    virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );
    

    実際にはこう書くこともできる

    throw( ... )
    

    1 つ目は拡張可能ではなく、2 つ目は野心的すぎ、3 つ目は仮想関数を記述するときに実際に意味するものです。

  3. レガシーコード

    別のライブラリに依存するコードを書く場合、何かひどい問題が起こったときに何が起こるかは実際にはわかりません。

    int lib_f();
    
    void g() throw( k_too_small_exception )
    { 
       int k = lib_f();
       if( k < 0 ) throw k_too_small_exception();
    }
    

    g will terminate, when lib_f() throws. This is (in most cases) not what you really want. std::terminate() should never be called. It is always better to let the application crash with an unhandled exception, from which you can retrieve a stack-trace, than to silently/violently die.

  4. Write code that returns common errors and throws on exceptional occasions.

    Error e = open( "bla.txt" );
    if( e == FileNotFound )
        MessageUser( "File bla.txt not found" );
    if( e == AccessDenied )
        MessageUser( "Failed to open bla.txt, because we don't have read rights ..." );
    if( e != Success )
        MessageUser( "Failed due to some other error, error code = " + itoa( e ) );
    
    try
    {
       std::vector<TObj> k( 1000 );
       // ...
    }
    catch( const bad_alloc& b )
    { 
       MessageUser( "out of memory, exiting process" );
       throw;
    }
    

Nevertheless, when your library just throws your own exceptions, you can use exception specifications to state your intent.

おすすめ記事