无法反序列化升压图对象



我正在使用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;
    }
}

一如既往的

  • 从小处着手,逐步构建,并在每一步测试

发生意外故障时:

  • 消除原因(分而治之(

如果你这样做了,你会很快发现即使是

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

然后是

ia >> make_nvp("e", e);

将显示完全相同的问题,甚至没有任何数据。问题是QTableboost::multi_index_container派生,这破坏了它的序列化实现

这是Coliru上的最小复制器

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";
    }
}

打印

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

注意:错误实际上不是与关闭元素有关(W3C的良好格式检查也会告诉你这一点(

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

在Coliru上直播

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

我对你的图形样本也做了同样的处理。它起了作用(就测试而言(:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="12">
<graph class_id="0" tracking_level="0" version="0">
    <V>20</V>
    <E>60</E>
    <vertex_property class_id="1" tracking_level="0" version="0">
        <property_value>0</property_value>
        <property_base class_id="2" tracking_level="0" version="0">
            <property_value class_id="3" tracking_level="0" version="0">
                <count>0</count>
                <item_version>0</item_version>
            </property_value>
            <property_base class_id="4" tracking_level="0" version="0">
                <property_value>0</property_value>
                <property_base class_id="5" tracking_level="0" version="0"></property_base>
            </property_base>
        </property_base>
    </vertex_property>
    <vertex_property>
        <property_value>0</property_value>
        <property_base>
            <property_value>
                <count>0</count>
                <item_version>0</item_version>
            </property_value>
            <property_base>
                <property_value>0</property_value>
                <property_base></property_base>
            </property_base>
        </property_base>
    </vertex_property>
    <vertex_property>
        <property_value>0</property_value>
        <property_base>
            <property_value>
                <count>0</count>
                <item_version>0</item_version>
            </property_value>
            <property_base>
                <property_value>0</property_value>
                <property_base></property_base>
            </property_base>
        </property_base>
    </vertex_property>
    <vertex_property>
        <property_value>0</property_value>
        <property_base>
            <property_value>
                <count>0</count>
                <item_version>0</item_version>
            </property_value>
            <property_base>
                <property_value>0</property_value>
                <property_base></property_base>
            </property_base>
        </property_base>
    </vertex_property>
    <vertex_property>
        <property_value>0</property_value>
        <property_base>
            <property_value>
                <count>0</count>
                <item_version>0</item_version>
            </property_value>
            <property_base>
                <property_value>0</property_value>
                <property_base></property_base>
            </property_base>
        </property_base>
    </vertex_property>
 ....
    <v>15</v>
    <edge_property>
        <property_value>
            <count>0</count>
            <value_version></value_version>
            <position object_id="_56"></position>
            <pointer class_id="-1"></pointer>
        </property_value>
        <property_base></property_base>
    </edge_property>
    <u>19</u>
    <v>5</v>
    <edge_property>
        <property_value>
            <count>0</count>
            <value_version></value_version>
            <position object_id="_57"></position>
            <pointer class_id="-1"></pointer>
        </property_value>
        <property_base></property_base>
    </edge_property>
    <u>19</u>
    <v>17</v>
    <edge_property>
        <property_value>
            <count>0</count>
            <value_version></value_version>
            <position object_id="_58"></position>
            <pointer class_id="-1"></pointer>
        </property_value>
        <property_base></property_base>
    </edge_property>
    <u>19</u>
    <v>13</v>
    <edge_property>
        <property_value>
            <count>0</count>
            <value_version></value_version>
            <position object_id="_59"></position>
            <pointer class_id="-1"></pointer>
        </property_value>
        <property_base></property_base>
    </edge_property>
    <graph_property></graph_property>
</graph>
</boost_serialization>

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

最新更新