无法获得提升图对象反序列化

时间:2015-08-02 01:42:17

标签: c++ boost

我正在使用boost图库。我需要序列化一个 图形对象,稍后再读出来。但我发现了我的 程序无法与XML归档程序一起正常工作。它 总是抛出异常的说法:

  

XML开始/结束标记   不匹配 - 位置。

我没有定义一个名为的标签 我的序列化代码中的"position"。我不知道怎么回事 解决它。这是一个演示 这个问题。

types.h中

#ifndef TYPES_H
#define TYPES_H

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/adj_list_serialize.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/variant.hpp>
#include <boost/ref.hpp>

using namespace boost;
namespace bmi = boost::multi_index;

class QTable; //forward declaration
typedef QTable Eligibility;

//观测类型
enum Observation{present,absent,idle};

//1)图模型的定义
enum vertex_BatteryLevel_t {vertex_BatteryLevel};
enum vertex_ObservationHistory_t {vertex_ObservationHistory};
enum edge_QFunction_t {edge_QFunction};
enum edge_Eligibility_t {edge_Eligibility};

namespace boost {
    BOOST_INSTALL_PROPERTY(vertex,BatteryLevel);
    BOOST_INSTALL_PROPERTY(vertex,ObservationHistory);
    BOOST_INSTALL_PROPERTY(edge,QFunction);
    BOOST_INSTALL_PROPERTY(edge,Eligibility);
}

typedef property<vertex_BatteryLevel_t,int,
    property<vertex_ObservationHistory_t,std::deque<Observation>,
        property<vertex_index_t,int>
    > 
> vertex_state;
typedef property<edge_QFunction_t,QTable,
    property<edge_Eligibility_t,Eligibility>
> edge_qfunction;
typedef adjacency_list<
    vecS,setS,directedS, //结点用vecS因为无需动æ€æ”¹å˜ç»“点个数,用setS表示边为了强调是简å•å›¾ï¼ˆä¸¤ä¸ªç»“点之间一个方å‘çš„è¾¹åªèƒ½æœ‰ä¸€æ¡ï¼‰
    vertex_state, //节点的电é‡å’Œè§‚测历å²
    edge_qfunction  //æ¯ä¸ªæœ‰å‘边对应一个ublas::matrix<double>对象属性 
> Graph;

//2)Q函数的定义
//行为类型
enum NotSensing{off=-2,recharge=-1};
typedef variant<int,NotSensing> Action; //action={å„个方å‘,off,recharge}

//state=<历å²è§‚测,电池电é‡>
struct Status {
    friend class boost::serialization::access;
    template<class Archive> void serialize(Archive & ar,const unsigned int version);

    //从结点id->观测历å²çš„映射
    //æ¯ä¸€ä¸ªæ—¶åˆ»çš„历å²è§‚测顺åºæ˜¯ä¼ æ„Ÿå™¨æœ¬èº«ï¼ŒæŒ‰ç…§è¿­ä»£å™¨é¡ºåºçš„其他传感器观测
    typedef std::map<int,std::deque<Observation> > HistoryType;
    HistoryType history;
    int batteryLevel;       //电池电é‡
    Status() {}
    Status(const HistoryType & h,const int & bl);
    Status(const Status & s);
    ~Status() {}
    friend bool operator<(const Status & idx1,const Status & idx2);
    friend bool operator==(const Status & idx1,const Status & idx2);
};

template<class Archive>
inline void Status::serialize(Archive & ar,const unsigned int)
{
    ar & boost::serialization::make_nvp("history",history);
    ar & boost::serialization::make_nvp("batteryLevel",batteryLevel);
}

struct QTableElem {
    friend class boost::serialization::access;
    template<class Archive> void serialize(Archive &,const unsigned int) {}
    Status status;
    Action myaction, youraction;
    double value;
    QTableElem(const Status & s,const Action & ma,const Action & ya,double v)
    : status(s),myaction(ma),youraction(ya),value(v) {}
};

typedef QTableElem EligibilityElem;

//因为typedefä¸èƒ½circular dependent所以需è¦å®šä¹‰ä¸ªç±»ç»§æ‰¿å…¶ä¸­ä¸€ä¸ªtypedef。
class QTable : public bmi::multi_index_container <
    QTableElem,
    bmi::indexed_by <
        bmi::ordered_unique<
            bmi::composite_key<
                QTableElem,
                bmi::member<QTableElem,Status,&QTableElem::status>,
                bmi::member<QTableElem,Action,&QTableElem::myaction>,
                bmi::member<QTableElem,Action,&QTableElem::youraction>
            >
        >,
        bmi::ordered_non_unique<bmi::member<QTableElem,Status,&QTableElem::status> >
    >
> {};

namespace boost {
    namespace serialization {
        template<class Archive> inline void save_construct_data(Archive & ar,const QTableElem * e,const unsigned int) {
            ar << boost::serialization::make_nvp("status",e->status);
            ar << boost::serialization::make_nvp("myaction",e->myaction);
            ar << boost::serialization::make_nvp("youraction",e->youraction);
            ar << boost::serialization::make_nvp("value",e->value);
        }
        template<class Archive> void load_construct_data(Archive & ar,QTableElem * e,const unsigned int) {
            Status s;
            Action ma,ya;
            double v;
            ar >> boost::serialization::make_nvp("status",s);
            ar >> boost::serialization::make_nvp("myaction",ma);
            ar >> boost::serialization::make_nvp("youraction",ya);
            ar >> boost::serialization::make_nvp("value",v);
            ::new(e) QTableElem(s,ma,ya,v);
        }
    }
}

#endif

types.cpp

#include <stdexcept>
#include "types.h"

Status::Status(const Status::HistoryType & h,const int & bl)
:history(h),batteryLevel(bl)
{
}

Status::Status(const Status & s)
:history(s.history),batteryLevel(s.batteryLevel)
{
}

bool operator<(const Status & idx1,const Status & idx2)
{
#ifndef NDEBUG
    assert(idx1.history.size() == idx2.history.size());
#endif
    Status::HistoryType::const_iterator it,it2;
    for(it = idx1.history.begin(), it2 = idx2.history.begin() ; it != idx1.history.end() && it2 != idx2.history.end() ; it++,it2++) {
#ifndef NDEBUG
        assert(it->first == it2->first);
        assert(it->second.size() == it2->second.size());
#endif
        std::deque<Observation>::const_iterator itt,itt2;
        for(itt = it->second.begin(), itt2 = it2->second.begin() ; itt != it->second.end() && itt2 != it2->second.end() ; itt++,itt2++) {
            if(*itt < *itt2) return true;
            if(*itt > *itt2) return false;
        }
    }
#ifndef NDEBUG
    assert(it == idx1.history.end() && it2 == idx2.history.end());
#endif
    return false;
}

bool operator==(const Status & idx1,const Status & idx2)
{
#ifndef NDEBUG
    assert(idx1.history.size() == idx2.history.size());
#endif
    Status::HistoryType::const_iterator it, it2;
    for(it = idx1.history.begin(), it2 = idx2.history.begin() ; it != idx1.history.end() && it2 != idx2.history.end() ; it++,it2++) {
#ifndef NDEBUG
        assert(it->first == it2->first);
        assert(it->second.size() == it2->second.size());
#endif
        std::deque<Observation>::const_iterator itt,itt2;
        for(itt = it->second.begin(), itt2 = it2->second.begin() ; itt != it->second.end() && itt2 != it2->second.end() ; itt++,itt2++) {
            if(*itt != *itt2) return false;
        }
    }
#ifndef NDEBUG
    assert(it == idx1.history.end() && it2 == idx2.history.end());
#endif
    return true;
}

的main.cpp

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include "types.h"

//compile with "g++ main.cpp types.cpp -I. -o test -lboost_serialization"

int main()
{
    using boost::serialization::make_nvp;
    {
        //load vertices
        std::ifstream in("../graph.txt");
        if (false == in.is_open())
            throw std::runtime_error("invalid graph model file!");

        typedef graph_traits<Graph>::vertices_size_type size_type;
        size_type n_vertices;
        in >> n_vertices;
        std::istream_iterator<std::pair<size_type, size_type> > input_begin(in), input_end;
        Graph g(input_begin, input_end, n_vertices);
        //serialize the graph object
        {
            std::ofstream out("../test.xml");
            if (false == out.is_open()) throw std::runtime_error("invalid file!");
            boost::archive::xml_oarchive oa(out);
            oa << make_nvp("graph", g);
        }
    }

    {
        //deserialize from the file
        std::ifstream xml("../test.xml");
        if (false == xml.is_open())
            throw std::runtime_error("invalid file!");
        {
            boost::archive::xml_iarchive ia(xml);
            Graph g;
            try {
                ia >> make_nvp("graph", g);
            }
            catch (boost::archive::archive_exception const& ae)
            {
                std::cout << "Error: " << ae.code << ":'" << ae.what() << "'\n";
            }
        }
    }
}

namespace std {
    template <typename T> istream & operator>>(istream & in,pair<T,T>& p) {
        in >> p.first >> p.second;
        return in;
    }
}

1 个答案:

答案 0 :(得分:4)

一如既往

  • 从小处开始,逐步构建,并在每一步测试

如果出现意外故障:

  • 消除原因(分而治之)。

如果你这样做了,你很快就发现了

Eligibility e;
oa << make_nvp("e", e);

接着是

ia >> make_nvp("e", e);
即使没有任何数据,

也会显示完全相同的问题。问题是来自QTable的{​​{1}} 派生,这打破了它的序列化实现。

这里是最小的复制者 Live On Coliru

boost::multi_index_container

打印

namespace bmi = boost::multi_index;

struct QTableElem {
    template<class Archive> void serialize(Archive &ar,const unsigned int) {
        ar & boost::serialization::make_nvp("dummy", dummy);
    }
    int dummy;
};

class QTable : public bmi::multi_index_container<
    QTableElem,
    bmi::indexed_by<
        bmi::ordered_unique<bmi::member<QTableElem,int,&QTableElem::dummy> >
    >
> {};

int main()
{
    using boost::serialization::make_nvp;
    {
        std::ofstream out("test.xml");
        boost::archive::xml_oarchive oa(out);

        QTable obj;
        oa << make_nvp("graph", obj);
    }

    try {
        std::ifstream xml("test.xml");
        boost::archive::xml_iarchive ia(xml);
        QTable obj;
        ia >> make_nvp("graph", obj); 
    } catch (boost::archive::archive_exception const& ae) {
        std::cout << "Error: " << ae.code << ":'" << ae.what() << "'\n";
    }
}
  

注意:错误实际上与关闭元素的关系(W3C&#39;良好格式检查也会告诉你)

现在,要修复SSCCE,只需删除继承:

<强> Live On Coliru

g++ -std=c++03 -O2 -Wall -pedantic -pthread main.cpp -lboost_system -lboost_serialization && ./a.out
Error: 1:'position'

我为您的图表示例做了同样的事情。它起作用(根据测试完全执行):

typedef bmi::multi_index_container<
    QTableElem,
    bmi::indexed_by<
        bmi::ordered_unique<bmi::member<QTableElem,int,&QTableElem::dummy> >
    >
> QTable;

如果您想查看它,请参阅:https://gist.github.com/sehe/093f823937486eb99d2f