【问题标题】:Boost Spirit Symbol throws access violationBoost Spirit Symbol 引发访问冲突
【发布时间】:2015-02-20 20:36:20
【问题描述】:

您好,我是 Boost Spirit 的新手,我遇到了 qi::symbol 对象的问题。

#include <iostream>
#include <vector>

#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_DEBUG_OUT std::cerr

#include <boost/config/warning_disable.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp> 
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_symbols.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
struct Thing
{
    Thing() = default; 

    Thing(std::string s, std::string t)
    :
        one(s),
        two(t)
    {
    }


    std::string one;
    std::string two;
};

BOOST_FUSION_ADAPT_STRUCT(
    Thing,
    (std::string, one)
    (std::string, two)
)

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
struct parse_things : qi::grammar<Iterator, Thing(), ascii::space_type>
{
    parse_things() : parse_things::base_type(keyword)
    {
        qi::symbols<char, Thing> keywords;
        keywords.add
            ("One", Thing("ThingOne","ThingTwo"))
            ("Two", Thing("ThingTwo","ThingOne"));

        keyword %= keywords;
        BOOST_SPIRIT_DEBUG_NODE(keyword);
    }

    qi::rule<Iterator, Thing(), ascii::space_type> keyword;
};

int main(int argc, const char *argv[])
{
    Thing t;
    std::string s("One");
    std::string s2("Two");
    parse_things<std::string::const_iterator> parser;

    bool r = qi::phrase_parse(
            std::cbegin(s),
            std::cend(s),
            parser,
            ascii::space,
            t);

    assert(r == true);
    assert(t.one == "ThingOne");
    assert(t.two == "ThingTwo");
    assert(t.two == "ThingOne");
    assert(t.one == "ThingTwo");

    return 0;
}

这在 Visual Studio 2014 Update 4 上为我编译,但在解析时引发访问冲突。我做错了什么?

【问题讨论】:

    标签: boost boost-spirit boost-spirit-qi


    【解决方案1】:

    你应该做

    qi::symbols<char, Thing> keywords;
    

    结构的成员,而不是构造函数中的临时局部。您的解析器将对 symbols 对象中的 trie 数据结构有过时的引用。

    带有更多测试的稍微简化的程序:

    Live On Coliru

    //#define BOOST_SPIRIT_DEBUG
    #define BOOST_SPIRIT_DEBUG_OUT std::cerr
    
    #include <boost/fusion/adapted/struct.hpp>
    #include <boost/fusion/include/io.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/qi_symbols.hpp>
    #include <iostream>
    #include <vector>
    
    struct Thing
    {
        std::string one;
        std::string two;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        Thing,
        (std::string, one)
        (std::string, two)
    )
    
    namespace qi    = boost::spirit::qi;
    namespace phx   = boost::phoenix;
    namespace ascii = boost::spirit::ascii;
    
    template <typename Iterator>
    struct parse_things : qi::grammar<Iterator, Thing(), ascii::space_type>
    {
        parse_things() : parse_things::base_type(keyword)
        {
            keywords.add
                ("One", Thing{"ThingOne","ThingTwo"})
                ("Two", Thing{"ThingTwo","ThingOne"});
    
            keyword %= keywords;
            BOOST_SPIRIT_DEBUG_NODE(keyword);
        }
    
        qi::symbols<char, Thing> keywords;
        qi::rule<Iterator, Thing(), ascii::space_type> keyword;
    };
    
    int main()
    {
        const parse_things<std::string::const_iterator> parser;
    
        for (std::string const s : { "One", "Two", "Three" })
        {
            auto f = begin(s), l = end(s);
            Thing data;
    
            bool ok = qi::phrase_parse(f,l,parser,ascii::space,data);
    
            std::cout << s << ": " << std::boolalpha << ok << ", " << boost::fusion::as_vector(data) << '\n';
            if (f != l)
                std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
        }
    }
    

    打印

    One: true, (ThingOne ThingTwo)
    Two: true, (ThingTwo ThingOne)
    Three: false, ( )
    Remaining unparsed: 'Three'
    

    【讨论】:

    • 现在看来很明显了!非常感谢!
    • 谢谢,你帮我解决了类似的问题。你能解释一下为什么符号解析器必须在成员范围内声明,而其他多字符解析器(如this tutorial语法中的“qi::uint_type uint_;”)可以在解析器构造函数中声明为临时本地的吗?
    • @die_hoernse 符号是有状态的,并被“按引用”使用。我不实际上相信该教程链接中的用法是完全安全的。我认为它在技术上可能是 UB,除非以某种方式没有采用无状态解析器 by-ref 。如果你不让符号成为成员,你会得到这个:stackoverflow.com/questions/30744000/…
    • @sehe 我恳请您告诉我,您在最基本的官方提升精神教程中是在开玩笑。但感谢您指出这一点。不过感觉就像一个雷区。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 2015-12-08
    • 2017-01-17
    相关资源
    最近更新 更多