【问题标题】:C++ Boost.Serialization error for hash_map with custom objects as key以自定义对象为键的 hash_map 的 C++ Boost.Serialization 错误
【发布时间】:2014-07-08 23:27:58
【问题描述】:

我需要序列化一个包含 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 对象时,错误是:terminate call after throwing an instance of 'boost::archive::archive_exception' what(): 未注册的类 - 未注册或导出的派生类

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

【问题讨论】:

    标签: c++ serialization boost


    【解决方案1】:

    在使用前尝试在存档中注册 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,因为您当然不希望这个号码反序列化
    • 我将管理 Items 的生命周期/分配作为练习(我不知道您希望如何组织所有权语义)

    完整代码

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

    【讨论】:

      猜你喜欢
      • 2010-11-06
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-21
      • 2019-09-13
      • 2010-10-28
      相关资源
      最近更新 更多