使用 phoenix 构造时调用析构函数
Destructor gets called when using phoenix construct
我正在开发一个 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;
}
析构函数在foo
规则的属性上运行;那是在它被复制到引用的属性之后。
由于您的 Foo
class 违反了三规则,这会导致问题。 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&)’
简而言之:
- 使用零规则或{三|五}规则编写卫生 classes
- 不要在 Spirit 语法中进行动态分配。它会让你伤心。
- 不要执行语义操作(Boost Spirit: "Semantic actions are evil"?)
这是通过实施三规则的快速修复版本:
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;
};
这里有一个使用零规则的稍微不那么快速和肮脏的方法:
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;
}
}
我正在开发一个 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;
}
析构函数在foo
规则的属性上运行;那是在它被复制到引用的属性之后。
由于您的 Foo
class 违反了三规则,这会导致问题。 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&)’
简而言之:
- 使用零规则或{三|五}规则编写卫生 classes
- 不要在 Spirit 语法中进行动态分配。它会让你伤心。
- 不要执行语义操作(Boost Spirit: "Semantic actions are evil"?)
这是通过实施三规则的快速修复版本:
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;
};
这里有一个使用零规则的稍微不那么快速和肮脏的方法:
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;
}
}