GCC 5.0のC++関係機能

https://gcc.gnu.org/gcc-5/changes.html

網羅的ではなく、気になったものだけ抽出して書いています。

C++11、C++14関係の対応状況は、cpprefjpサイトにもほぼ反映しました。

  • C++14を全実装
    • 変数テンプレート
    • 宣言時のメンバ初期化を持つ型の集成体初期化を許可
    • constexprの制限緩和
    • サイズ付きデアロケーション
  • -std=c++14オプションが使えるようになる。旧-std=c++1yオプションは非推奨。
  • C++11周りのライブラリサポート改善
    • std::listsize()メンバ関数が、デフォルトでO(1)になる
    • std::dequestd::vector<bool>に、ステートフルアロケータのサポートを追加。
    • iostreamのクラスに、ムーブとswapのサポートを追加。
    • std::alignstd::aligned_unionのサポートを追加。
    • is_trivially_*系の型特性を追加。
    • IOマニピュレータのput_timehexfloatdefaultfloatのサポートを追加。
    • std::isblankジェネリックロケールで使えるようになった。
    • std::shared_ptrのアトミック操作をサポート。
    • std::notify_all_at_thread_exit()系の、スレッド終了時にfutureを準備完了状態にする機能をサポート。
  • C++14ライブラリ
    • is_final型特性を実装
  • C++14後のLibrary Fundamentals TSの機能を追加。std::experimental名前空間で定義される。
    • anyクラス(boost::anyと同じ)
    • apply関数(タプルを展開して関数実行)
    • sample関数(コンテナからN個の要素をランダム選択)
    • search関数(文字列特化した探索アルゴリズム)
    • 変数テンプレートの型特性をいくつか
    • not_fn関数(not1not2を統合し、改善したもの)
  • 新しい警告オプションとして、-Wsuggest-final-typesが入る。「このクラスにはfinalを付けたほうがいいよ」とオススメしてくれる。
  • 拡張機能として、乱数の分布クラスlogistic_distribution(ロジスティック分布)とuniform_on_sphere_distribution(球状の一様分布、Boost.Randomにある)を追加。
  • IntelのCilk Plusをフルサポート。並列関係の新しい言語拡張。
  • Clangにもある__has_includeをサポート。ヘッダファイルがあるかどうかを調べられる。

GCC 4.9がリリースされました

GCC 4.9.0 released, full of improved C++11 and C++14 features

C++14対応が主ですが、C++11にも、以下のサポート改善が入っています。

  • <regex>をサポート
  • <map><set><unordered_map><unordered_set>に、ステートフルアロケータのサポートを追加

<regex>は、昨年のGoogle Summer of Codeで学生さんが実装したものですね。お金を出してくれたGoogleと、実装してくれたTim Shenさんに感謝です。

オンラインコンパイラWandboxでも、すでにGCC 4.9を使える状態になっています。

Spirit.Qiのパーサーをautoで受けると吹っ飛ぶ問題が解決した

GCCにバグ報告:最適化オプションを付けるとBoost.Spiritのプログラムが吹っ飛ぶ

先日GCCにバグ報告した件ですが、GCCのバグではありませんでした。@k_satodaさんに教えてもらいました。

Boost.Spirit.Qiが内部で使っているBoost.Protoの式テンプレートが、引数を(一時オブジェクトであっても)コピーせずに参照で持ってるのが原因だそうです。

http://twitter.com/k_satoda/status/420606068025069568

パーサー式をautoで受けると、パーサー式が持ってる参照がシャローコピーされ、寿命が尽きた一時オブジェクトへの参照が発生して、未定義動作になります。なので、qi::ruleを使わずautoで受ける場合は、boost::proto::deep_copy()関数でパーサー式をラップして、パーサー式をディープコピーする必要があります。

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;
namespace proto = boost::proto;

int main()
{
    const std::string input = "hello:";

    auto rule = proto::deep_copy(*(qi::char_ - ':') >> ':');

    std::string::const_iterator it = input.begin();
    std::string result;
    if (qi::parse(it, input.end(), rule, result)) {
        std::cout << "parse successful" << std::endl;
    }
    else {
        std::cout << "parse failed" << std::endl;
    }
}

とりあえず、先日のバグ報告は、私のほうで取り下げました。

このことはBoost.Spiritの公式ブログにも載っています。

Zero to 60 MPH in 2 seconds! - Spirit

これはC++11のautoが考慮されていないBoost.Spirit V2の問題で、これに対処するために、Boost 1.55.0後のtrunkには、Spiritのディレクトリに、BOOST_SPIRIT_AUTOというマクロが定義されています(<boost/spirit/include/support_auto.hpp><boost/spirit/home/support/auto.hpp>をインクルードする)。

BOOST_SPIRIT_AUTO(qi, comment, "/*" >> *(char_ - "*/") >> "*/");

このマクロは内部で、パーサー式をディープコピーしてcommentという変数に代入します。

しかしこんなマクロは書きたくないので、現在開発中のBoost.Spirit X3では、この問題を解決してC++11のautoをふつうに使えるようにする予定だそうです。

参照

GCCにバグ報告:最適化オプションを付けるとBoost.Spiritのプログラムが吹っ飛ぶ

Bug 59709 - break program behavior with optimization

GCC 4.8.1、GCC 4.8.2で最適化オプション(たとえば-O2)を付けると、Boost.Spiritを使ったコードが吹っ飛びます。

吹っ飛びますというのは、プログラムの次の行が実行されず、どこかに行ってしまう、ということです。セグメンテーションフォルトで落ちることもあれば、if文で実行される節がelseの方に行ってしまったり(正しくはthenの方)もします。環境によって挙動が変わります。

再現コードは以下:

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main()
{
    const std::string input = "hello:";

    auto rule = *(qi::char_ - ':') >> ':';

    std::string::const_iterator it = input.begin();
    std::string result;
    if (qi::parse(it, input.end(), rule, result)) {
        std::cout << "parse successful" << std::endl;
    }
    else {
        std::cout << "parse failed" << std::endl;
    }
}

最適化を付けないで実行すると、このプログラムは「parse successful」を出力します。これが正しい挙動です。

これを-O2で実行すると、MacPorts GCC 4.8.1環境では何も出力されませんでした(if文がthenでもelseでもないどこかに行った)。WandboxのGCC 4.8.1、GCC 4.8.2ではelse節が実行され「parse failed」が出力されます。

ルールの型としてautoを使わず、qi::ruleを使えばこの問題は発生しません。

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main()
{
    const std::string input = "hello:";

    qi::rule<std::string::const_iterator, std::string()> rule = *(qi::char_ - ':') >> ':';

    std::string::const_iterator it = input.begin();
    std::string result;
    if (qi::parse(it, input.end(), rule, result)) {
        std::cout << "parse successful" << std::endl;
    }
    else {
        std::cout << "parse failed" << std::endl;
    }
}

このプログラムは、最適化オプションを付けても付けなくても、「parse successful」が出力されます。

Windows向けのQt 5.2に付属しているMinGWGCC 4.8を使っていて、この問題でしばらく悩んでいました。Windows環境でBoost.SpiritとQtを使う場合、しばらくコンパイラはVisual C++を使うのがいいですね。ちなみにClangではこの問題は発生しません。

Boost.Spiritを使わない再現コードが書けなかったので、仕方なくこれらのコードをそのままGCCに報告しました。

追記

解決しました。

GCC 4.8.2リリース

GCC 4.8 Release Series


GCC 4.8.2がリリースされました。
これは、GCC 4.8シリーズのバグフィックスバージョンになります。


私が報告したバグも2件修正されています。

Bug 58098 - wrong return value of normal_distribution::min()
Bug 58302 - compilation error : std::negative_binomial_distribution::operator(e, p)


id:melponが運営・開発しているオンラインコンパイラWandboxでも、すでにGCC 4.8.2を使用できます。
Wandbox


GCC 4.8.1 - C++11全実装バージョン

GCC 4.8 Release Series Changes, New Features, and Fixes


アナウンスが遅くなりましたが、GCC 4.8.1がリリースされています。
このバージョンでは、decltypeのN3276仕様に対応、メンバ関数の左辺値 or 右辺値によるオーバーロードという機能が追加され、C++11の言語機能が全実装されました。

ライブラリ(libstdc++)の方で、正規表現ライブラリと、いくつかのType Traitsの実装が不足していますが、実用上十分だと思います。


GCC 4.8がリリースされた

GCC 4.8 Release Series Changes, New Features, and Fixes


C++周りの変更は以下。


言語

  • thread_localキーワードのサポートを追加。
  • 属性構文のサポートを追加。GCCに元々あった独自属性も、C++11属性の構文で提供されるようになりました。
  • alignas属性のサポートを追加。
  • 継承コンストラクタのサポートを追加。
  • C++1yの実験的サポートのために、「-std=c++1y」コンパイルオプションを追加。このオプションをオンにすることで、N3386で提案された「戻り値型を推論する関数宣言構文」が利用可能になります。


ライブラリ(libstdc++)

  • forward_listを、標準のアロケータ要件を満たすよう修正(allocator_traits)
  • this_thread::sleep_for()、this_thread::sleep_until()、this_thread::yield()を、「--enable-libstdcxx-time」オプションを付けることなく定義されるようにした。
  • の改善
    • normal_distributionを、SSE最適化
    • 新しいx86プロセッサ上で、random_deviceにRNG命令を使用するようにした
  • 拡張の乱数ライブラリとしてを追加
    • SSE最適化されたメルセンヌ・ツイスターの実装であるsimd_fast_mersenne_twister_engineを追加
    • 分布クラスを色々追加。beta_distribution, normal_mv_distribution, rice_distribution, nakagami_distribution, pareto_distribution, k_distribution, arcsine_distribution, hoyt_distribution
  • プロセスが異常終了したときに出力される診断メッセージを無効にするための「--disable-libstdcxx-verbose」オプションを追加。実行ファイルのサイズを減らすのに使える。


GCCを含む、コンパイラC++11対応状況は、以下のページにまとめてあります:
コンパイラの実装状況 - cpprefjp
言語的には、GCCはあと「メンバ関数の左辺値/右辺値修飾」だけですね。


GCCに報告してたバグが修正された:std::advance()の負数チェック

Bug 53515 - InputIterator version std::advance needs negative check
GCCとVCにバグ報告: std::advance()の負数チェック


少し前に報告してた問題が修正されました。
assertを1行足すだけですが。


GCCとVCにバグ報告: std::advance()の負数チェック

Bug 53515 - InputIterator version std::advance needs negative check
InputIterator/ForwardIteratorバージョンのstd::advanceに負数チェックがない


些細なものですがバグ報告しました。


VCとGCCにバグ報告 - std::arrayのtuple_elementとget()の境界チェック

Bug 53080 - tuple interface to std::array doesn't check bounds

std::arrayに対するstd::tuple_elementの特殊化で、境界チェックが行われていない


std::arrayに対するstd::tuple_elementの特殊化とstd::get()関数のオーバーロードでは、インデックス値IがarrayのサイズNより小さくない場合、プログラムは不適格である、という仕様があります。
GCC 4.7.0のlibstdc++にその境界チェックが両方なかったので、報告しておきました。
VC10は、std::get()の方にはstatic_assertで境界チェックがあったので、std::tuple_elementの方だけ報告しました。