使用phoenix construct

时间:2015-04-22 13:00:24

标签: c++ boost boost-spirit-qi boost-phoenix

我正在开发一个Boost Spirit Qi项目,该项目使用phoenix::construct创建一个具有指向另一个对象的指针的对象。我注意到使用phoenix::construct在某个时刻调用了析构函数(我猜测函数的结尾)。为什么析构函数会被调用?我该如何解决这个问题?

注意:这不是我的实际代码,我做了一个玩具示例,所以它不会那么长

物件

class Bar
{
public:
    Bar(int y)
    {
        this->x = y;
    }

    ~Bar()
    {
    }

    int x;
};

class Foo
{
public:

    Foo()
    {
    }

    Foo(Bar* bar) : _bar(bar)
    {
    }

    ~Foo()
    {
        delete this->_bar;
    }

    void DoStuff()
    {
        std::cout << this->_bar->x << std::endl;
    }

private:
    Bar *_bar;
};

语法

template <typename Iterator>
struct TestGrammar : qi::grammar < Iterator, Foo(), ascii::space_type >
{
    TestGrammar() : TestGrammar::base_type(foo)
    {
        foo = bar[qi::_val = phoenix::construct<Foo>(qi::_1)];
        bar = qi::double_[qi::_val = phoenix::new_<Bar>(qi::_1)];
    }

    qi::rule < Iterator, Foo(), ascii::space_type > foo;
    qi::rule < Iterator, Bar*(), ascii::space_type> bar;
};

致电代码

std::getline(std::cin, string);

iter = string.begin();
end = string.end();

bool result = qi::phrase_parse(iter, end, grammar, space, f);

if (result)
{
    State s;
    f.DoStuff();
}
else
{
    std::cout << "No Match!" << std::endl;
}

1 个答案:

答案 0 :(得分:1)

析构函数运行在foo规则的属性上;在将其复制到引用的属性之后。

由于您的Foo课程违反了三级规则,因此会导致问题。 Foo不应该是可复制的(或实施深层复制)。

标记为:

class Foo : public boost::noncopyable {

将显示语法复制Foo

/home/sehe/custom/boost_1_57_0/boost/proto/transform/default.hpp|154 col 9| error: use of deleted function ‘Foo& Foo::operator=(const Foo&)’

简而言之:

  1. 用零度规则或{三|五}规则编写卫生类
  2. 不要在Spirit语法中进行动态分配。它会给你带来悲伤。
  3. 不要进行语义操作(Boost Spirit: "Semantic actions are evil"?
  4. 通过实施三法则,这是一个快速而又肮脏的固定版本:

    <强> Live On Coliru

    struct Foo {
        Foo(Bar *bar = 0) : _bar(bar) {}
        Foo(Foo const& o) : _bar(new Bar(*o._bar)) {}
        Foo& operator=(Foo const& o) { 
            Foo tmp;
            tmp._bar = new Bar(*o._bar);
            std::swap(tmp._bar, _bar);
            return *this;
        }
    
        ~Foo() { delete _bar; }
    
        void DoStuff() { std::cout << _bar->x << std::endl; }
    
      private:
        Bar *_bar;
    };
    

    使用零度规则,这里的快速和肮脏程度稍低:

    <强> Live On Coliru

    struct Foo {
        using PBar = boost::shared_ptr<Bar>;
        Foo(PBar bar = {}) : _bar(bar) {}
    
        void DoStuff() { std::cout << _bar->x << std::endl; }
    
    private:
        PBar _bar;
    };
    

    完整代码

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <boost/make_shared.hpp>
    
    namespace qi      = boost::spirit::qi;
    namespace phoenix = boost::phoenix;
    namespace ascii   = boost::spirit::ascii;
    
    struct Bar {
        Bar(int y) { this->x = y; }
        ~Bar() {}
    
        int x;
    };
    
    struct Foo {
        using PBar = boost::shared_ptr<Bar>;
        Foo(PBar bar = {}) : _bar(bar) {}
    
        void DoStuff() { std::cout << _bar->x << std::endl; }
    
      private:
        PBar _bar;
    };
    
    template <typename Iterator>
    struct TestGrammar : qi::grammar<Iterator, Foo(), ascii::space_type>
    {
        TestGrammar() : TestGrammar::base_type(foo)
        {
            using namespace qi;
            foo = bar     [ _val = phoenix::construct<Foo::PBar>(_1) ] ;
            bar = double_ [ _val = phoenix::new_<Bar>(_1)      ] ;
        }
    
        qi::rule<Iterator, Foo(), ascii::space_type> foo;
        qi::rule<Iterator, Bar*(), ascii::space_type> bar;
    };
    
    int main() {
        std::string input;
        std::getline(std::cin, input);
    
        using It = std::string::const_iterator;
        It iter = input.begin();
        It end = input.end();
    
        TestGrammar<It> grammar;
        Foo f;
        bool result = qi::phrase_parse(iter, end, grammar, ascii::space, f);
    
        if (result) {
            //State s;
            f.DoStuff();
        } else {
            std::cout << "No Match!" << std::endl;
        }
    }