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
をふつうに使えるようにする予定だそうです。