C++ 反序列化PortableBinaryArchive时遇到问题

C++ 反序列化PortableBinaryArchive时遇到问题,c++,c++11,serialization,vector,cereal,C++,C++11,Serialization,Vector,Cereal,我面临一个std::length异常,使用谷物库反序列化一个包含我自己的类的std::vector。我想如果我给出一些代码,这是最简单的。这是我的班级: #包括“谷物/档案/便携式二进制文件.hpp” #包括“grane/archives/json.hpp” #包括“谷物/类型/向量.hpp” 枚举类myType{ 无,未设置,类型1,类型2,类型3 }; 类myClass { 公众: myClass(); myClass(大小); ~myClass(); std::向量idxs; myType

我面临一个std::length异常,使用谷物库反序列化一个包含我自己的类的std::vector。我想如果我给出一些代码,这是最简单的。这是我的班级:

#包括“谷物/档案/便携式二进制文件.hpp”
#包括“grane/archives/json.hpp”
#包括“谷物/类型/向量.hpp”
枚举类myType{
无,未设置,类型1,类型2,类型3
};
类myClass
{
公众:
myClass();
myClass(大小);
~myClass();
std::向量idxs;
myType数据类型;
bool是有效的;
//此方法让Gray知道要序列化哪些数据成员
模板
作废序列化(存档和存档)
{
档案(谷物NVP(dtype)、谷物NVP(isvalid)、谷物NVP(idxs));
}
受保护的:
私人:
};
idxs成员不一定总是具有相同的大小。 经过一些计算之后,我得到了一个

std::vector<myClass> allData;
然而,当向量成员第一次出现在序列化中时,它不适用于JSON。但这可能完全无关

archive(CEREAL_NVP(idxs), CEREAL_NVP(dtype), CEREAL_NVP(isvalid));
现在我的问题是:

1) 这就是序列化处理谷物的方式吗

2) 是否需要添加更多序列化函数?例如,到枚举类

致意
AverageCoder

在序列化代码方面,您的类没有任何问题。您不需要为枚举提供序列化,它是通过
谷物/types/common.hpp自动包含的。字段序列化的顺序并不重要

您的错误在于在执行加载和保存时未正确使用存档。谷物处理与流的所有接口,因此您不应直接在谷物存档上使用流操作器(即
)。再看一下谷物网站上的示例,您会注意到,每当与谷物档案进行交互时,都是通过
()
操作员完成的

您还应该确保在处理二进制数据的流上操作时使用了适当的标志(
std::ios::binary
),这可以防止一些难以调试的问题

下面是一个使用您的类的工作示例,其中我将保存到内存流而不是文件,但原理相同:

#include <cereal/archives/portable_binary.hpp>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
#include <algorithm>
#include <sstream>

enum class myType {
    None, unset, Type1, Type2, Type3
};

class myClass
{
public:
  myClass() = default;
  myClass( myType mt, size_t i ) : isvalid( true ), dtype( mt ),
                                idxs( i )
  {
    std::iota( idxs.begin(), idxs.end(), i );
  }

  std::vector<size_t> idxs;
  myType dtype;
  bool isvalid;

  // This method lets cereal know which data members to serialize
  template<class Archive>
  void serialize(Archive & archive)
  {
    archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs));
  }
};

int main(int argc, char* argv[])
{
  std::vector<myClass> allData = {{myType::None, 3}, {myType::unset, 2}, {myType::Type3, 5}};

  // When dealing with binary archives, always use the std::ios::binary flag
  // I'm using a stringstream here just to avoid writing to file
  std::stringstream ssb( std::ios::in | std::ios::out | std::ios::binary );
  {
    cereal::PortableBinaryOutputArchive arb(ssb);
    // The JSON archive is only used to print out the data for display
    cereal::JSONOutputArchive ar(std::cout);

    arb( allData );
    ar( allData );
  }

  {
    cereal::PortableBinaryInputArchive arb(ssb);
    cereal::JSONOutputArchive ar(std::cout);

    std::vector<myClass> data;
    arb( data );

    // Write the data out again and visually inspect
    ar( data );
  }

  return 0;
}

指定std::ios::binary标志没有帮助。使用运算符()而不是运算符>>也没有进行更改。我认为我必须更深入地挖掘我的示例,或者尝试在同一个应用程序中加载。在同一个应用程序中序列化和反序列化没有任何区别。它也失败了。下一步我将尝试以下内容:我的allData std::vector保留的大小比最终的大小要大(大小<保留),这可能是序列化的问题。我将根据我的发现更新这里的问题,哪些有效,哪些无效。谷物在加载期间适当调整向量大小-您的保留容量不会产生任何影响。我鼓励大家再看一看我发布的示例和谷类食品网站上的示例,根据你的描述,我认为你在某个地方犯了一个简单的接口错误,导致了你的问题。简单更新一下:我还没有找到问题所在,但目前的情况是:在idxs成员的myClass中更改了一些计算之后,新的输出可以作为portableBinaryArchive被Groove读取。allData向量中的项数现在只有原来的一半(现在myClass的项数为~8K,以前为~16K)。但是,通过JSON打开失败的旧归档文件(有效)和通过portableBinaryArchive打开新归档文件,我在调试器中看不到结构上的差异。我有点不知所措,我不认为这是一个大小的问题。因为问题可能在我这边,我会接受这个答案,因为它回答了我的问题,所以我在这里没有做任何根本错误:-)再次感谢,@Azoth。
#include <cereal/archives/portable_binary.hpp>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
#include <algorithm>
#include <sstream>

enum class myType {
    None, unset, Type1, Type2, Type3
};

class myClass
{
public:
  myClass() = default;
  myClass( myType mt, size_t i ) : isvalid( true ), dtype( mt ),
                                idxs( i )
  {
    std::iota( idxs.begin(), idxs.end(), i );
  }

  std::vector<size_t> idxs;
  myType dtype;
  bool isvalid;

  // This method lets cereal know which data members to serialize
  template<class Archive>
  void serialize(Archive & archive)
  {
    archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs));
  }
};

int main(int argc, char* argv[])
{
  std::vector<myClass> allData = {{myType::None, 3}, {myType::unset, 2}, {myType::Type3, 5}};

  // When dealing with binary archives, always use the std::ios::binary flag
  // I'm using a stringstream here just to avoid writing to file
  std::stringstream ssb( std::ios::in | std::ios::out | std::ios::binary );
  {
    cereal::PortableBinaryOutputArchive arb(ssb);
    // The JSON archive is only used to print out the data for display
    cereal::JSONOutputArchive ar(std::cout);

    arb( allData );
    ar( allData );
  }

  {
    cereal::PortableBinaryInputArchive arb(ssb);
    cereal::JSONOutputArchive ar(std::cout);

    std::vector<myClass> data;
    arb( data );

    // Write the data out again and visually inspect
    ar( data );
  }

  return 0;
}
{
    "value0": [
        {
            "dtype": 0,
            "isvalid": true,
            "idxs": [
                3,
                4,
                5
            ]
        },
        {
            "dtype": 1,
            "isvalid": true,
            "idxs": [
                2,
                3
            ]
        },
        {
            "dtype": 4,
            "isvalid": true,
            "idxs": [
                5,
                6,
                7,
                8,
                9
            ]
        }
    ]
}{
    "value0": [
        {
            "dtype": 0,
            "isvalid": true,
            "idxs": [
                3,
                4,
                5
            ]
        },
        {
            "dtype": 1,
            "isvalid": true,
            "idxs": [
                2,
                3
            ]
        },
        {
            "dtype": 4,
            "isvalid": true,
            "idxs": [
                5,
                6,
                7,
                8,
                9
            ]
        }
    ]
}