【问题标题】:why my boost serialization failed with input stream error?为什么我的 boost 序列化因输入流错误而失败?
【发布时间】:2022-01-02 16:33:50
【问题描述】:

我有一个复杂的类,需要序列化。

我使用boost.serialization

该类是一个单例类,具有多个功能。单例不是关键部分,因为我尝试了一些简单的单例类的简单代码,效果很好。

// static_player.h
#pragma once
#include <map>
#include <unordered_set>
#include <vector>
#include <memory>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/unordered_map.hpp>
#include <boost/serialization/unordered_set.hpp>
#include <boost/serialization/map.hpp>

#include "util/file_util.h"
#include "struct/struct_util.hpp"

namespace util:trade_util {
    typedef std::unordered_map<std::string, std::unordered_map<std::string, std::unordered_map<std::string, double>>> NTKD; // map of name_ticker_key_value
    typedef std::unordered_map<std::string, std::unordered_map<std::string, std::unordered_map<std::string, std::string>>> NTKS; // map of name_ticker_key_value
    typedef std::unordered_map<std::string, std::map<int32_t, std::unordered_map<std::string, std::unordered_map<std::string, double>> > > NDTKD;
    typedef std::unordered_map<std::string, std::map<int32_t, std::unordered_map<std::string, std::unordered_map<std::string, std::string>> > > NDTKS;
    
    class StaticPlayer {
     private:
      StaticPlayer();
      StaticPlayer(const StaticPlayer&) = delete;
      StaticPlayer(const StaticPlayer&&) = delete;
      virtual ~StaticPlayer();
 
      class DM {
       public:
        DM() {}
        DM(NTKD * numeric_data, NTKS * string_data) : numeric_data_(numeric_data), string_data_(string_data) {}
        virtual ~DM() = default;
        inline double get_numeric(const std::string & name, const std::string& ticker, const std::string& key) const;
        inline std::string get_string(const std::string & name, const std::string& ticker, const std::string& key) const;
      private:
        NTKD* numeric_data_;
        NTKS* string_data_;
        friend class boost::serialization::access;
        template<class Archive>
        void serialize(Archive & ar, const unsigned int version) {
          ar & numeric_data_;
          ar & string_data_;
        }
      };

     public:
      static StaticPlayer& Inst() { static StaticPlayer um; return um; }
      double query_numeric(const std::string&name, const std::string&ticker, int32_t date, const std::string& key);
      std::string query_string(const std::string&name, const std::string&ticker, int32_t date, const std::string& key);
      void operator=(const StaticPlayer&) = delete;
      DM* operator[](int32_t date);
      void load_config(const std::set<std::string> & fset);
      void load_config(bool simple = false);

     private:
      double special_query(const std::string&ticker, int32_t date, const std::string& key);
     private:
      bool loaded_ = false;
      std::map<int32_t, DM*> umap_;
      // std::mutex mut_;
      NDTKD numeric_data_; //  name : date : ticker : key : value
      NDTKS string_data_; //  name : date : ticker : key : value
      std::unordered_map<std::string, std::string> fill_na_method_;  // name : fill_na
      std::map<int32_t, std::unordered_map<std::string, std::unordered_map<int32_t, std::string> >> rank_map_;
      std::unordered_set<std::string> tickers_, chains_;

      friend class boost::serialization::access;
      template<class Archive>
      void serialize(Archive & ar, const unsigned int version) {
        ar & loaded_; ar & umap_; ar & numeric_data_;
        ar & string_data_; ar & fill_na_method_;
        ar & rank_map_; ar & tickers_; ar & chains_;
        // ar & mut_;
      }
    };
}

main.cpp 是:

#include "./static_player.h"
void write_univ() {
  auto & u = util::trade_util::StaticPlayer::Inst();
  u.load_config();
  std::ofstream ofs("a");
  boost::archive::text_oarchive oa(ofs);
  oa << u;
  
  std::ifstream ifs("a");
  boost::archive::text_iarchive ia(ifs);
  util::trade_util::StaticPlayer& u2 = (util::trade_util::StaticPlayer::Inst());
  ia >> u2; 
  for (const auto & ticker : u2.get_tickers()) cout << ticker << endl;
}

int main() {
  write_univ();
}

错误信息是:

terminate called after throwing an instance of 'boost::archive::archive_exception'
  what():  input stream error
[1]    20341 abort (core dumped)  ./a.out

我已经阅读了所有在 Internet 上可以找到的内容,但仍然无法弄清楚原因。

你能帮忙吗?

【问题讨论】:

    标签: c++ serialization boost boost-serialization


    【解决方案1】:

    哎呀,从/到单例序列化可能不是一个好主意。为什么不让 load 返回一个实例,如果必须的话,你可以选择用它来替换单例?

    真正的问题是序列化的一个典型陷阱:如果您将序列化/反序列化放在同一个范围内,请确保您的存档已完成(并写入磁盘),然后再尝试将其加载回来。 ..:

    void write_univ()
    {
        {
            std::ofstream                 ofs("a");
            boost::archive::text_oarchive oa(ofs);
    
            auto& u = util::trade_util::StaticPlayer::Inst();
            u.load_config();
            oa << u;
        }
    
        {
            std::ifstream                   ifs("a");
            boost::archive::text_iarchive   ia(ifs);
            util::trade_util::StaticPlayer& u2 =
                util::trade_util::StaticPlayer::Inst();
            ia >> u2;
        }
    }
    

    就是这样。

    旁注

    另外,也许您应该尝试整理地图周围的“意大利面条”类型:

    template <typename T> using Dict = std::unordered_map<std::string, T>;
    template <typename T> using NTK  = std::unordered_map<std::string, Dict<T>>;
    template <typename T> using NDTK = std::unordered_map<std::string, std::map<int32_t, Dict<T>>>;
    
    using NTKD  = NTK<double>;
    using NTKS  = NTK<std::string>;
    using NDTKD = NDTK<double>;
    using NDTKS = NDTK<std::string>;
    

    然后这告诉我你基本上有像

    这样的直接记录
    struct Record {
         std::string name;
         int32_t id;
         variant<double, string> value;
    };
    

    您为什么不考虑使用具有两个索引的单个 Multi-Index 容器 - 或者甚至可以只使用 (name,id) 的一个组合键索引,如果您可以使用部分键(未指定的 id)进行查询喜欢吗?

    参见例如这个类似的例子Using boost multi index like relational DB

    独立测试:

    LiveUndead On Coliru

    // static_player.h
    //#pragma once
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/serialization/map.hpp>
    #include <boost/serialization/unordered_map.hpp>
    #include <boost/serialization/unordered_set.hpp>
    #include <boost/serialization/vector.hpp>
    #include <fstream>
    #include <memory>
    #include <set>
    #include <vector>
    
    //#include "util/file_util.h"
    //#include "struct/struct_util.hpp"
    
    namespace util::trade_util {
        template <typename T> using Dict = std::unordered_map<std::string, T>;
        template <typename T> using NTK  = std::unordered_map<std::string, Dict<T>>;
        template <typename T> using NDTK = std::unordered_map<std::string, std::map<int32_t, Dict<T>>>;
    
        using NTKD  = NTK<double>;
        using NTKS  = NTK<std::string>;
        using NDTKD = NDTK<double>;
        using NDTKS = NDTK<std::string>;
    
        class StaticPlayer {
          private:
            StaticPlayer()                     = default;
            StaticPlayer(const StaticPlayer&)  = delete;
            StaticPlayer(const StaticPlayer&&) = delete;
            virtual ~StaticPlayer()            = default;
    
            class DM {
              public:
                DM() = default;
                DM(NTKD* numeric_data, NTKS* string_data)
                    : numeric_data_(numeric_data)
                    , string_data_(string_data)
                {
                }
                virtual ~DM() = default;
                [[nodiscard]] inline double
                get_numeric(const std::string& name, const std::string& ticker,
                            const std::string& key) const;
                [[nodiscard]] inline std::string
                get_string(const std::string& name, const std::string& ticker,
                           const std::string& key) const;
    
              private:
                NTKD* numeric_data_ = nullptr;
                NTKS* string_data_  = nullptr;
                friend class boost::serialization::access;
                template <class Archive>
                void serialize(Archive& ar, const unsigned int version)
                {
                    ar& numeric_data_;
                    ar& string_data_;
                }
            };
    
          public:
            static StaticPlayer& Inst()
            {
                static StaticPlayer um;
                return um;
            }
            double query_numeric(const std::string& name, const std::string& ticker,
                                 int32_t date, const std::string& key);
            std::string query_string(const std::string& name,
                                     const std::string& ticker, int32_t date,
                                     const std::string& key);
            void        operator=(const StaticPlayer&) = delete;
            DM*         operator[](int32_t date);
            void        load_config(const std::set<std::string>& fset);
            void        load_config(bool simple = false) {}
    
          private:
            double special_query(const std::string& ticker, int32_t date,
                                 const std::string& key);
    
          
            bool                   loaded_ = false;
            std::map<int32_t, DM*> umap_;
            // std::mutex mut_;
            NDTKD numeric_data_; //  name : date : ticker : key : value
            NDTKS string_data_;  //  name : date : ticker : key : value
            std::unordered_map<std::string, std::string>
                fill_na_method_; // name : fill_na
            std::map<int32_t,
                     std::unordered_map<std::string,
                                        std::unordered_map<int32_t, std::string>>>
                                            rank_map_;
            std::unordered_set<std::string> tickers_, chains_;
    
            friend class boost::serialization::access;
            template <class Archive>
            void serialize(Archive& ar, const unsigned int version)
            {
                ar& loaded_;
                ar& umap_;
                ar& numeric_data_;
                ar& string_data_;
                ar& fill_na_method_;
                ar& rank_map_;
                ar& tickers_;
                ar& chains_;
                // ar & mut_;
            }
        };
    } // namespace util::trade_util
    
    //#include "./static_player.h"
    void write_univ()
    {
        {
            std::ofstream                 ofs("a");
            boost::archive::text_oarchive oa(ofs);
    
            auto& u = util::trade_util::StaticPlayer::Inst();
            u.load_config();
            oa << u;
        }
    
        {
            std::ifstream                   ifs("a");
            boost::archive::text_iarchive   ia(ifs);
            util::trade_util::StaticPlayer& u2 =
                util::trade_util::StaticPlayer::Inst();
            ia >> u2;
        }
        // for (const auto& ticker : u2.get_tickers())
        // std::cout << ticker << std::endl;
    }
    
    int main() { write_univ(); }
    

    按预期工作。在我的机器上创建一个存档a,其中包含:

    22 serialization::archive 19 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0
    

    【讨论】:

      猜你喜欢
      • 2016-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      相关资源
      最近更新 更多