I face a std::length exception using the cereal library to deserialize a std::vector full of a class of my own. I think it's easiest if I give some code. This is my 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:
};
The idxs member is not necessarily always of the same size. After some calculations I then obtain a
std::vector<myClass> allData;
which I want to serialize and later deserialize in another application. This is my code for serialization:
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";
}
The generated data file is not null size and not all zero, so just from the looks it is fine. This is what I do to deserialize in the other application:
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";
}
When I run this deserialization code, I get an exception "std::length_error". Somehow related discussion to this error is here but to me it seems not to be relevant for my case. (Or is it?)
I tried to de-/serialize with separate load/save functions, because I was not sure whether this part of the cereal documentation applies here:
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).
I also tried to archive each vector element of the idxs member separately in a range based for loop (like it is done in cereal internally anyway), but both things didn't help.
Both applications are compiled with Visual Studio 2015 Update 3. I use the current cereal v1.2.2 but also tried with cereal v1.1.2 which gave me a bit-identical serialization result.
As an aside: It works with a cereal JSON archive. But only after I changed the serialization call to
archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs));
whereas it didn't work with JSON when the vector member came first on serialization. But this might be completely unrelated.
archive(CEREAL_NVP(idxs), CEREAL_NVP(dtype), CEREAL_NVP(isvalid));
Now my questions:
1) Is this the way serialization is supposed to work with cereal?
2) Do I need to add more serialization functions? E.g. to the enum class?
Best regards AverageCoder