0

我面临一个 std::length 异常,使用谷物库反序列化一个充满我自己的类的 std::vector。我认为如果我给出一些代码是最简单的。这是我的课:

#include "cereal/archives/portable_binary.hpp"
#include "cereal/archives/json.hpp"
#include "cereal/types/vector.hpp"

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

class myClass
{
public:
    myClass();
    myClass(size_t siz);
    ~myClass();
    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));
    }
protected:
private:
};

idxs 成员不一定总是具有相同的大小。经过一些计算,我得到一个

std::vector<myClass> allData;

我想序列化,然后在另一个应用程序中反序列化。这是我的序列化代码:

std::ofstream ofile(allDataFilename.c_str());
if (ofile.good())
{
    cereal::PortableBinaryOutputArchive theArchive(ofile);
    theArchive(allData);
    //ofilefp.close();   // Do not close because of RAII where dtor of cereal archive does some work on file!
}
else
{
    std::cout << "Serialization to portable binary archive failed. File not good." << "\n";
}

生成的数据文件不是空大小,也不是全为零,所以从外观上看是可以的。这是我在其他应用程序中反序列化的方法:

std::string allDataFilename("C:\\path\\to\\file\\data.dat");
std::ifstream infile(allDataFilename.c_str());
std::vector<myClass> myDataFromDisk;
if (infile.good())
{
    cereal::PortableBinaryInputArchive inArchive(infile);
    inArchive >> myDataFromDisk;
}
else
{
    std::cout << "Data file unavailable." << "\n";
}

当我运行这个反序列化代码时,我得到一个异常“std::length_error”。与此错误相关的讨论在这里,但对我来说似乎与我的情况无关。(或者是吗?)

我尝试使用单独的加载/保存函数进行反序列化/序列化,因为我不确定谷物文档的这一部分是否适用于此处:

如果可能,最好使用单一的内部序列化方法,尽管在必要时可以使用拆分方法(例如,在加载类时动态分配内存)。

我还尝试在基于范围的 for 循环中分别归档 idxs 成员的每个向量元素(就像它在内部谷物中完成的那样),但这两件事都没有帮助。

这两个应用程序都使用 Visual Studio 2015 Update 3 编译。我使用当前的谷物 v1.2.2,但也尝试使用谷物 v1.1.2,这给了我一个有点相同的序列化结果。

顺便说一句:它适用于谷物 JSON 档案。但只有在我将序列化调用更改为

archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs));

而当向量成员首先出现在序列化时,它不适用于 JSON。但这可能完全不相关。

archive(CEREAL_NVP(idxs), CEREAL_NVP(dtype), CEREAL_NVP(isvalid));

现在我的问题:

1)这是序列化应该与谷物一起使用的方式吗?

2)我需要添加更多的序列化函数吗?例如枚举类?

最好的问候 AverageCoder

4

1 回答 1

0

关于您的序列化代码,您的课程没有任何问题。您不需要为枚举提供序列化,它通过cereal/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;
}

及其输出:

{
    "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
            ]
        }
    ]
}
于 2017-02-16T19:48:40.577 回答