C++14標準ライブラリの小さな変更 その8

その1その2その3その4その5その6その7に引き続き、C++14の標準ライブラリに入った小さな変更を紹介していきます。

vectorとdequeの複数要素を挿入する操作の、強すぎる保証を緩和

C++11までこれらの関数は、以下のような保証をしていました。

要素の挿入操作で例外が発生した場合、副作用が発生しない

これはつまり、複数の要素を挿入する際に、後ろの方の要素が、コピーで例外を送出した場合、ここまで成功した挿入もなかったことにする、ということを意味します。これはバックアップ情報を持っておく必要があり、コストが高いこともあって、現実的でない強い保証です。

C++14では、挿入操作で例外が発生した場合には、例外が発生したその単一要素のみ、副作用が発生しない、という保証に変わりました。

コンテナの等値比較に、last2をとるequalアルゴリズムを使用するようになった

C++03およびC++11では、以下と同等の戻り値である、となっていました。

return distance(x.begin(), x.end()) == distance(y.begin(), y.end())
        && equal(x.begin(), x.end(), y.begin());

C++14では、std::equal()アルゴリズムに、last2を受け取るオーバーロードが追加されたので、それを使用します。

return equal(x.begin(), x.end(), y.begin(), y.end());

このlast2を受け取るオーバーロードは、一度の横断で、要素数が等しいかと、それらの要素が等しいかの両方を判定します。

C++11では、コンテナのsize()メンバ関数は、計算量が全てO(1)になったので、実際の実装ではdistance()の代わりにsize()メンバ関数が使用されていたでしょうから、パフォーマンスはとくに変わらないでしょう。

forward_listについては、Cの実装とゼロオーバーヘッドにするという目的があるため、size()メンバ関数を持っていません。そのため、distance()size()メンバ関数で置き換えて使用できなかったので、forward_listはこの変更でパフォオーマンスアップが期待できるでしょう(内部の実装用にlast2を受け取るequal()アルゴリズムを持っていなければ)。

async関数の戻り値の型に、decayを適用するようになった

C++11

namespace std {
  template <class F, class... Args>
  future<typename result_of<F(Args...)>::type>
    async(F&& f, Args&&... args);

  template <class F, class... Args>
  future<typename result_of<F(Args...)>::type>
    async(launch policy, F&& f, Args&&... args);
}

C++14

namespace std {
  template <class F, class... Args>
  future<
    typename result_of<
      typename decay<F>::type(typename decay<Args>::type...)
    >::type
  > async(F&& f, Args&&... args);

  template <class F, class... Args>
  future<
    typename result_of<
      typename decay<F>::type(typename decay<Args>::type...)
    >::type
  > async(launch policy, F&& f, Args&&... args);
}

ios_base::xallocがスレッドセーフになった

C++03

static int index = 0;
return index++;

C++14

static std::atomic<int> index(0);
return index++;

これでおわりにします

まだいくつかありますが、気にする必要のあるものはそれほどないので、このあたりで終わりにします。

さらに詳しく知りたい方は、cpprefjpのC++14対応まとめページからリンクを辿るか、cpprefjp/siteリポジトリのコミットログからC++14対応の歴史を抽出してください。