具有自定义对象作为键的hash_map的C ++ Boost.Serialization错误

时间:2014-05-20 15:35:22

标签: c++ serialization boost

我需要将包含hash_map的对象序列化为另一个对象作为键。用作键的对象是其他对象的基类。我已经在基类和派生类中实现了serialize()方法,并且每个派生类都继承了基类的序列化方法。情况类似于:

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/hash_map.hpp> 
#include <boost/serialization/base_object.hpp>

class Item {
protected:

    unsigned int _refc;
    static unsigned int _total_alloc;

//other code

private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
    ar & _refc;
    ar & _total_alloc;
    }
};

class StringItem : public Item {
private:
    string _s;

    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
    ar & boost::serialization::base_object<Item>(*this);    
    ar & _s;
    }

};

这是我需要序列化的类:

class TokenFinder : public Model {
public:

     TokenFinder(void);

     virtual ~TokenFinder(void);

     virtual void insert_item(Item *item);

private:
/** Map to store tokens together with their number of occurrences. 
*/
     __gnu_cxx::hash_map<Item *, unsigned long> _elements;
     unsigned long _element_count;

     friend class boost::serialization::access;
     template<class Archive>
     void serialize(Archive & ar, const unsigned int version)
     {
       ar & _elements; //Error when saved
       ar & _element_count;
 }
};

当我尝试序列化TokenFinder对象时,错误是:在抛出'boost :: archive :: archive_exception'的实例后调用terminate   what():未注册的类 - 未注册或导出的派生类

有什么建议吗?提前谢谢!

1 个答案:

答案 0 :(得分:1)

尝试在使用之前使用Archive注册Item的子类:

template<class Archive>
    void serialize(Archive & ar, unsigned)
    {
        ar.template register_type<StringItem>(); // THIS

        ar & boost::serialization::base_object<Model>(*this);    
        ar & _elements;
        ar & _element_count;
    }

查看 Live demo On Coliru

输出

22 serialization::archive 10 0 0 0 0 0 0 6 0 0 0 1 1 0
0 1 0
1 0 10 cow-jumped 6 1
2
3 0 4 moon 5 1
4
5 0 4 lazy 4 1
6
7 0 3 the 3 1
8
9 0 5 world 2 1
10
11 0 5 hello 1 0

注释

  • 我为std::unordered_map定义了序列化,因此您不再需要使用已弃用的GNU库扩展(另请参阅this bug-report/patch
  • 我评论了_total_alloc因为,当然,您不希望这个号码被反序列化
  • 我将Item的生命周期/分配作为练习进行管理(我不知道你希望如何组织所有权语义)。

完整代码

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <unordered_map>
#include <boost/serialization/collections_save_imp.hpp>
#include <boost/serialization/collections_load_imp.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/split_free.hpp>

namespace boost { namespace serialization {

    template<class Archive, typename... TArgs >
        inline void save(Archive & ar, std::unordered_map<TArgs...> const&t, unsigned) {
            boost::serialization::stl::save_collection<Archive, std::unordered_map<TArgs...> >(ar, t);
        }

    template<class Archive, typename... TArgs >
        inline void load(Archive & ar, std::unordered_map<TArgs...> &t, unsigned) {
            boost::serialization::stl::load_collection<Archive,
                std::unordered_map<TArgs...>,
                boost::serialization::stl::archive_input_map<
                    Archive, std::unordered_map<TArgs...> >,
                boost::serialization::stl::no_reserve_imp<std::unordered_map<TArgs...> >
                    >(ar, t);
        }

    // split non-intrusive serialization function member into separate
    // non intrusive save/load member functions
    template <class Archive, typename... TArgs>
        inline void serialize(Archive & ar, std::unordered_map<TArgs...> &t, unsigned file_version) {
            boost::serialization::split_free(ar, t, file_version);
        }
} }

#include <boost/serialization/base_object.hpp>

class StringItem;

class Item {
  protected:
    unsigned int _refc;
    static unsigned int _total_alloc;

    //other code
    Item() : _refc(0) { }
    virtual ~Item() {}

  private:
    friend class boost::serialization::access;

    template<class Archive>
        void serialize(Archive & ar, unsigned)
    {
        ar & _refc;
        //ar & _total_alloc; // wut? a static?!
    }
};

/*static*/ unsigned int Item::_total_alloc;

class StringItem : public Item {
  public:
    StringItem(std::string s = "") : _s(std::move(s)) { }
  private:
    std::string _s;

    friend class boost::serialization::access;
    template<class Archive>
        void serialize(Archive & ar, unsigned)
        {
            ar & boost::serialization::base_object<Item>(*this);    
            ar & _s;
        }
};


struct Model {
    virtual ~Model() {}
    template<class Archive> void serialize(Archive&r, unsigned) { }
};

class TokenFinder : public Model
{
  public:
    TokenFinder(void) : _element_count(0) {}

    virtual ~TokenFinder(void) {}

    virtual void insert_item(Item *item) { _elements[item] = _elements.size()+1; }

  private:
    /** Map to store tokens together with their number of occurrences. */
    std::unordered_map<Item*, unsigned long> _elements;
    unsigned long _element_count;

    friend class boost::serialization::access;
    template<class Archive>
        void serialize(Archive & ar, unsigned)
        {
            ar.template register_type<StringItem>();
            ar & boost::serialization::base_object<Model>(*this);    
            ar & _elements;
            ar & _element_count;
        }
};

int main()
{
    boost::archive::text_oarchive oa(std::cout);

    std::vector<StringItem> seed_data {
        {"hello"},{"world"},{"the"},{"lazy"},{"moon"}, {"cow-jumped"} 
    };



    TokenFinder tf;
    for(auto& si : seed_data)
        tf.insert_item(&si);

    oa << tf;

}