c++的提升.使用自定义对象作为键的hash_map序列化错误

C++ Boost.Serialization error for hash_map with custom objects as key

本文关键字:hash 序列化 错误 map 对象 c++ 自定义      更新时间:2023-10-16

我需要序列化一个对象,它包含一个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'实例后调用终止

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

尝试在使用前向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库扩展(另见此bug-report/patch)
  • 我注释掉了_total_alloc,因为,当然,你不希望这个数字反序列化
  • 我离开了管理Item s的生命周期/分配作为一个练习(我不知道你想要的所有权语义组织)

完整代码
#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;
}