麻烦反序列化谷物 PortableBinaryArchive
Trouble deserializing cereal PortableBinaryArchive
我遇到一个 std::length 异常,使用谷物库反序列化 std::vector 满是我自己的 class。我认为如果我提供一些代码是最简单的。这是我的 class:
#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"。以某种方式与此错误相关的讨论是 here,但对我而言,它似乎与我的情况无关。 (或者是吗?)
我尝试 de-/serialize 使用单独的 load/save 函数,因为我不确定谷物文档的这一部分是否适用于此处:
When possible, it is preferred to use a single internal serialize
method, though split methods can be used when it is necessary (e.g. to
dynamically allocate memory upon loading a class).
我还尝试在基于范围的 for 循环中分别存档 idxs 成员的每个向量元素(就像它在谷物内部完成的那样),但这两种方法都没有帮助。
这两个应用程序都是使用 Visual Studio 2015 Update 3 编译的。我使用当前的谷物 v1.2.2,但也尝试使用谷物 v1.1.2,这给了我一个有点相同的序列化结果。
顺便说一句:它适用于谷物 JSON 存档。但只有在我将序列化调用更改为
之后
archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs));
而当 vector 成员首先出现在序列化时,它不适用于 JSON。但这可能完全无关。
archive(CEREAL_NVP(idxs), CEREAL_NVP(dtype), CEREAL_NVP(isvalid));
现在我的问题:
1) 这就是序列化处理谷物的方式吗?
2) 是否需要添加更多序列化功能?例如。枚举 class?
此致
平均编码器
关于您的序列化代码,您的 class 没有任何问题。您不需要为枚举提供序列化,它会通过 cereal/types/common.hpp
自动包含。您的字段序列化的顺序无关紧要。
您的错误是在执行加载和保存时没有正确使用档案。 cereal 处理流的所有接口,因此您不应直接在 cereal 存档上使用流操作符(即 <<
或 >>
)。再看一下 cereal 网站上的示例,您会注意到,无论何时与 cereal archive 进行交互,都是通过 ()
运算符完成的。
您还应确保在处理二进制数据的流上操作时使用适当的标志 (std::ios::binary
) - 这可以防止一些难以调试的问题。
这是一个使用您的 class 的工作示例,其中我保存到 in-memory 流而不是文件,但原理是相同的:
#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
]
}
]
}
我遇到一个 std::length 异常,使用谷物库反序列化 std::vector 满是我自己的 class。我认为如果我提供一些代码是最简单的。这是我的 class:
#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"。以某种方式与此错误相关的讨论是 here,但对我而言,它似乎与我的情况无关。 (或者是吗?)
我尝试 de-/serialize 使用单独的 load/save 函数,因为我不确定谷物文档的这一部分是否适用于此处:
When possible, it is preferred to use a single internal serialize method, though split methods can be used when it is necessary (e.g. to dynamically allocate memory upon loading a class).
我还尝试在基于范围的 for 循环中分别存档 idxs 成员的每个向量元素(就像它在谷物内部完成的那样),但这两种方法都没有帮助。
这两个应用程序都是使用 Visual Studio 2015 Update 3 编译的。我使用当前的谷物 v1.2.2,但也尝试使用谷物 v1.1.2,这给了我一个有点相同的序列化结果。
顺便说一句:它适用于谷物 JSON 存档。但只有在我将序列化调用更改为
之后archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs));
而当 vector 成员首先出现在序列化时,它不适用于 JSON。但这可能完全无关。
archive(CEREAL_NVP(idxs), CEREAL_NVP(dtype), CEREAL_NVP(isvalid));
现在我的问题:
1) 这就是序列化处理谷物的方式吗?
2) 是否需要添加更多序列化功能?例如。枚举 class?
此致 平均编码器
关于您的序列化代码,您的 class 没有任何问题。您不需要为枚举提供序列化,它会通过 cereal/types/common.hpp
自动包含。您的字段序列化的顺序无关紧要。
您的错误是在执行加载和保存时没有正确使用档案。 cereal 处理流的所有接口,因此您不应直接在 cereal 存档上使用流操作符(即 <<
或 >>
)。再看一下 cereal 网站上的示例,您会注意到,无论何时与 cereal archive 进行交互,都是通过 ()
运算符完成的。
您还应确保在处理二进制数据的流上操作时使用适当的标志 (std::ios::binary
) - 这可以防止一些难以调试的问题。
这是一个使用您的 class 的工作示例,其中我保存到 in-memory 流而不是文件,但原理是相同的:
#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
]
}
]
}