【问题标题】:boost spirit V2 qi bug associated with optimization level提升精神V2 气与优化级别相关的错误
【发布时间】:2014-01-12 20:38:19
【问题描述】:

我在业余时间开发我的代码。最好在调试模式下。最近,当我尝试构建发布版本时,我得到了错误(运行时,输出:1\n2\n 然后失败)。我找到了包含错误的一段代码(如下),我发现该错误仅在优化级别为-Os, -Ofast, -O2, -O3 而不是-O, -O0, -O1, -Og 时发生。在发布模式下,我的调试能力受到限制。错误的原因是什么?发现此类错误的方法是什么?

#!/usr/bin/env bash -vex WARN="-W -Wall -Wextra" INCLUDE="-isystem /c/libs/boost-trunk" OPT="-O2" g++ -x c++ - - std=gnu++1y $INCLUDE

$WARN $OPT -o a

#include <iterator>
#include <string>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>

using namespace boost::spirit;

template< typename Iterator >
struct skipper
        : qi::grammar< Iterator >
{

    skipper();

private :

    typename skipper::base_type::start_type skipper_;

};

template< typename Iterator >
skipper< Iterator >::skipper()
    : skipper::base_type(skipper_, "skipper") 
{
    std::cerr << 1 << std::endl;
    auto const ana =
            *~qi::char_('*') > +qi::char_('*')
            ;
    std::cerr << 2 << std::endl;
    skipper_ =
            qi::space
            | ("/*" > ana > *(~qi::char_("/*") > ana) > '/')
            | ("//" > *(qi::char_ - qi::eol) > (qi::eol | qi::eoi))
            ; // R"(\s+|(\/\*[^*]*\*+([^/*][^*]*\*+)*\/)|(\/\/[^\r\n]*))"
    std::cerr << 3 << std::endl;
}

using input_type = std::string;
using input_iterator_type = std::istreambuf_iterator< typename input_type::value_type >;
using base_iterator_type = multi_pass< input_iterator_type >;

template struct skipper< base_iterator_type >;

using skipper_type = skipper< base_iterator_type >;

int main()
{
    skipper_type const skipper_;
    std::cerr << 4 << std::endl;
    return EXIT_SUCCESS;
}
__EOF

gcc -v 2&gt;&amp;1 | tail -n1:

gcc version 4.8.1 (rev5, Built by MinGW-W64 project) 

【问题讨论】:

  • 我使用 valgrind 来解决这些问题。 valgrind --db-attach=yes 最有帮助(当然在 linux 上)。但是,我的设置坏了,所以这次我只是在编辑器中检查了代码:/

标签: g++ compiler-optimization boost-spirit boost-spirit-qi


【解决方案1】:

这是您代码中的错误,编译器或优化级别没有问题。

最重要的是表达式模板(例如 Boost Proto 使用的模板,因此也被 Boost Spirit 使用)。它们仅在其封闭的完整表达式的末尾有效 [1]

典型的解决方法是:

 BOOST_SPIRIT_AUTO(ana, *~qi::char_('*') > +qi::char_('*'));

您可以在这里找到它:http://svn.boost.org/svn/boost/trunk/libs/spirit/example/qi/typeof.cpp,它是在这篇博文的 cmets 中首次介绍的:http://boost-spirit.com/home/articles/qi-example/zero-to-60-mph-in-2-seconds/

我测试的显式修复(在我的盒子上运行良好,valgrind 中没有警告):

auto const ana = boost::proto::deep_copy(
        *~qi::char_('*') > +qi::char_('*'))
        ;

Spirit X3 承诺去除这个疣。有点相关,我认为 Protox11 也通过始终了解引用来消除这个问题。


[1] Grep 延长临时工寿命的标准。表达式模板保留对所使用的文字的引用(其余的仍然具有值语义),但临时对象不绑定到 (const) 引用。所以他们超出了范围。 Undefined Behaviour结果

【讨论】:

  • 关于脚注:为什么优化会影响错误的存在?
  • 没有!这只是未定义的行为,它仅发生在 /appear to work/ 上。这就是为什么 valgrind/purify 等如此重要的原因。
  • Linux 用户很幸运,因为他们可以使用 valgrind 这样的免费工具。
  • 在boost trunk中(下个版本应该是boost.org/libs/spirit/example/qi/typeof.cpp)我从#include &lt;boost/spirit/include/support_auto.hpp&gt;找到boost::spirit::qi::copy,也解决了问题。
  • *不是来自指定的标题。我的错,对不起。但无论如何都存在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多