Search code examples
c++boostboost-spiritboost-spirit-qi

boost::spirit::multi_pass crash with predicate and alternative


Running the following code results in a crash. Why?

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

using namespace boost::spirit;
typedef multi_pass<
            std::string::const_iterator,
            iterator_policies::default_policy<
                iterator_policies::first_owner,
                iterator_policies::no_check,
                iterator_policies::buffering_input_iterator,
                iterator_policies::split_std_deque>>
        string_mp_iterator;

int main() {
    std::string input = "234";
    string_mp_iterator input_begin(input.begin()),
            input_end((string_mp_iterator()));
    qi::rule<string_mp_iterator, boost::variant<int, double>()> r =
            &qi::lit('1') >> qi::int_ | qi::double_;
    qi::parse(input_begin, input_end, r);
    return 0;
}

To reproduce the crash I seem to need to have both a predicate and subsequent alternative, to be using a multi_pass iterator, and for the input to not satisfy the predicate.

I get the feeling that I'm somehow using multi_pass incorrectly here, but I don't see what the problem is exactly.


Solution

  • Simply fix the initializer for the end iterator.

    string_mp_iterator input_end(input.end());
    

    Since it's not an input iterator, you cannot use a default constructed iterator legally.

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/support_multi_pass.hpp>
    
    using namespace boost::spirit;
    typedef multi_pass<
        std::string::const_iterator,
        iterator_policies::default_policy<
            iterator_policies::first_owner, iterator_policies::no_check,
            iterator_policies::buffering_input_iterator,
            iterator_policies::split_std_deque>>
        string_mp_iterator;
    
    int main() {
        std::string input = "234";
        string_mp_iterator input_begin(input.begin()),
                           input_end(input.end());
        qi::rule<string_mp_iterator, boost::variant<int, double>()> r = &qi::lit('1') >> qi::int_ | qi::double_;
        qi::parse(input_begin, input_end, r);
    }