C++11がもたらす新しい特性(3)——キーワードnoexcept

2692 ワード

1キーワードnoexcept


C++11から、多くのコードにキーワードnoexceptがあることがわかります.例えばstd::initializer_listのデフォルトのコンストラクション関数で、noexceptが使用されています.
      constexpr initializer_list() noexcept
      : _M_array(0), _M_len(0) { }

このキーワードは、関数に異常が発生しないことをコンパイラに伝えます.これは、コンパイラがプログラムをより最適化するのに役立ちます.実行時にnoexecpt関数が外部に例外を放出した場合(関数内部で例外がキャプチャされ、処理が完了した場合、例外は放出されません)、プログラムは直接終了し、std::terminate()関数が呼び出され、この関数内部でstd::abort()がプログラムを終了します.

2 C++の異常処理


C++における異常処理は,実行時にコンパイルでない場合に検出される.実行時検出を実現するために、コンパイラは追加のコードを作成しますが、これはプログラムの最適化を妨げます.実際には、一般的に2つの異常放出方式がよく使われています.
  • 操作または関数が異常を放出する可能性があります.
  • 操作または関数が異常を放出することはできません.

  • 後者の方式では、従来のC++バージョンではthrow()がよく用いられ、C++11ではnoexceptに置き換えられている.
        void swap(Type& x, Type& y) throw()   //C++11 
        {
            x.swap(y);
        }
        void swap(Type& x, Type& y) noexcept  //C++11
        {
            x.swap(y);
        }

    3条件付きnoexcecpt


    2節ではnoexceptを単独で用い,限定されたswap関数に異常が絶対に発生しないことを示す.しかしながら、使用方法は、一定の条件下で異常が発生しないことを示すより柔軟にすることができる.
        void swap(Type& x, Type& y) noexcept(noexcept(x.swap(y)))    //C++11
        {
            x.swap(y);
        }

    x.swap(y)を操作して異常が発生しない場合、関数swap(Type&x,Type&y)は必ず異常が発生しないことを示します.
    より良い例はstd::pairの移動割当関数(move assignment)であり、タイプT 1およびT 2の移動割当中に異常が発生しなければ、移動構造関数に異常は発生しないことを示している.
        pair& operator=(pair&& __p)
        noexcept(__and_,
                        is_nothrow_move_assignable<_t2>>::value)
        {
            first = std::forward(__p.first);
            second = std::forward(__p.second);
            return *this;
        }

    4 noexceptはいつ使えばいいですか?


    noexceptを使用すると、関数や操作に異常が発生しないことを示し、コンパイラにより大きな最適化空間を与えます.しかし、noexceptを加えることで効率が上がるわけではなく、足が大きくなっても卵を引っ張りやすい.次の場合、noexceptの使用を奨励します.
  • モバイルコンストラクタ
  • 移動割当関数(move assignment)
  • 構造関数(destructor).ここで、新しいバージョンのコンパイラでは、構造関数はデフォルトでキーワードnoexceptを付けています.次のコードは、コンパイラが構造関数にキーワードnoexceptを付けるかどうかを検出します.
  •     struct X
        {
            ~X() { };
        };
        
        int main()
        {
            X x;
        
            // This will not fire even in GCC 4.7.2 if the destructor is
            // explicitly marked as noexcept(true)
            static_assert(noexcept(x.~X()), "Ouch!");
        }
  • リーフ関数(Leaf Function).リーフ関数とは,関数内部にスタック空間を割り当てず,他の関数も呼び出さず,不揮発性レジスタも格納せず,異常も処理しないことをいう.

  • 最後に、上記でない場合や自信がない場合は、noexceptionを簡単に使用しないでください.
    転載先:https://www.cnblogs.com/sword03/p/10020344.html