【发布时间】:2018-07-21 03:13:28
【问题描述】:
上下文:我有一个树状结构,表示我想使用boost::serialization 序列化的 Expr 的 AST。主要问题是所有类都有非默认构造函数和 const 子级。为了克服这个问题,我遵循了文档并重载了 load_construct_data 和 save_construct_data(最终完成了所有工作)。
我的问题是关于代码中的 Mul 类。为了分解代码,我开发了一个模板类Op2,用于通过这些类上的CRTP 定义操作符,例如Add 或Mul(此处仅显示Mul)。在Mul::serialize中,我直接将Expr注册为Mul的基类,完全跳过Op2。 代码有效,valgrind 很高兴,但它正确吗?还是 boost::serialization 需要完整的类层次结构?
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/serialization.hpp>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
//forward declaration of my structs
struct Expr;
struct Mul;
struct Int;
//forward declarations of custom boost functions to friend them in the class
namespace b_ser = boost::serialization;
namespace boost {
namespace serialization {
template <class Archive>
void load_construct_data(Archive &ar, Mul *e, const unsigned int);
template <class Archive>
void save_construct_data(Archive &ar, const Mul *a, const unsigned int);
template <class Archive>
void load_construct_data(Archive &ar, Int *e, const unsigned int);
template <class Archive>
void save_construct_data(Archive &ar, const Int *a, const unsigned int);
} // namespace serialization
} // namespace boost
//memory manager
std::vector<std::unique_ptr<Expr>> pool;
// AST
struct Expr {
virtual ~Expr() {}
virtual std::vector<Expr const *> children() const = 0;
virtual std::string identity() const = 0;
void print(int p) const {
std::cout << std::setw(p) << ' ';
std::cout << identity() << "\n";
for (auto a_kid : children()) {
a_kid->print(p + 2);
}
}
void self_register() const {
if (std::find_if(pool.begin(), pool.end(), [this](auto const &stored_ptr) {
return this == stored_ptr.get();
}) == pool.end()) {
pool.push_back(std::unique_ptr<Expr>(const_cast<Expr *>(this)));
}
for (auto ptr : children()) {
ptr->self_register();
}
}
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {}
};
struct Int : Expr {
int const n;
std::vector<Expr const *> children() const override { return {}; }
std::string identity() const override {
return "Int[" + std::to_string(n) + "]@";
}
Int(int nn) : n(nn) {}
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &boost::serialization::base_object<Expr>(*this);
}
template <class Archive>
friend void b_ser::save_construct_data(Archive &ar, const Int *i,
const unsigned int) {
ar << i->n;
}
template <class Archive>
friend void b_ser::load_construct_data(Archive &ar, Int *i,
const unsigned int) {
int n;
ar >> n;
::new (i) Int(n);
}
};
template <class T> struct Op2 : Expr {
std::vector<Expr const *> children() const override { return {l, r}; }
std::string identity() const override { return T::message; }
Op2(Expr const *ll, Expr const *rr) : l(ll), r(rr) {}
protected:
Expr const *l;
Expr const *r;
};
struct Mul : Op2<Mul> {
using Op2::Op2;
static auto const constexpr message = "Mul";
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &boost::serialization::base_object<Expr>(*this);
}
template <class Archive>
friend void b_ser::save_construct_data(Archive &ar, const Mul *a,
const unsigned int) {
ar << a->l;
ar << a->r;
}
template <class Archive>
friend void b_ser::load_construct_data(Archive &ar, Mul *e,
const unsigned int) {
Expr *l, *r;
ar >> l;
ar >> r;
::new (e) Mul(l, r);
e->self_register();
}
};
template <class T, class... Args> T *store(Args... args) {
auto to_store = std::make_unique<T>(std::forward<Args>(args)...);
auto raw_ptr = to_store.get();
pool.push_back(std::move(to_store));
return raw_ptr;
}
BOOST_CLASS_EXPORT(Expr)
BOOST_CLASS_EXPORT(Int)
BOOST_CLASS_EXPORT(Mul)
int main(int argc, char *argv[]) {
{
auto deux = store<Int>(2);
auto trois = store<Int>(3);
auto m_23 = store<Mul>(trois, deux);
auto quatre = store<Int>(4);
auto root = store<Mul>(m_23, quatre);
Expr *e_root = root;
root->print(2);
std::ofstream of("arxiv");
boost::archive::text_oarchive oa(of);
oa << e_root;
}
std::cout << "==================="
<< "\n";
{
std::ifstream isf("arxiv");
boost::archive::text_iarchive is(isf);
Expr *expr;
is >> expr;
expr->print(2);
}
return 0;
}
【问题讨论】:
标签: c++ c++11 boost boost-serialization