I encountered the following runtime error with cereal when trying serialize the class with JSON:
libc++abi: terminating with uncaught exception of type cereal::RapidJSONException: rapidjson internal assertion failure: IsObject()
Interestingly, absolutely same code works with binary archive.
I'm trying to make a template function for my code. Something like that:
enum SER_Archive_Type {BIN, JSON};
template<typename T>
bool SerializeObject(T &obj, std::string filename, const SER_Archive_Type TYPE) {
std::fstream fs;
switch (TYPE) {
case JSON: {
fs.open(filename, std::ios::out);
if (fs.is_open()) {
cereal::JSONOutputArchive jarchive(fs);
jarchive(obj);
fs.close();
return true;
} else {
return false;
}
break;
}
case BIN: {
fs.open(filename, std::ios::out | std::ios::binary);
if (fs.is_open()) {
cereal::BinaryOutputArchive barchive(fs);
barchive(obj);
fs.close();
return true;
} else {
return false;
}
break;
}
default:
break;
}
return false;
}
template<typename T>
bool DeserializeObject(T &obj, std::string filename, const SER_Archive_Type TYPE) {
std::fstream fs;
switch (TYPE) {
case JSON: {
fs.open(filename, std::ios::in);
if (fs.is_open()) {
cereal::JSONInputArchive jarchive(fs);
jarchive(obj);
fs.close();
return true;
} else {
return false;
}
break;
}
case BIN: {
fs.open(filename, std::ios::in | std::ios::binary);
if (fs.is_open()) {
cereal::BinaryInputArchive barchive(fs);
barchive(obj);
fs.close();
return true;
} else {
return false;
}
break;
}
default:
break;
}
return false;
}
Example code looks like that:
int main()
{
uint32_t a = 123;
SerializeObject(a, "a.bin", BIN); // ok
uint32_t b;
DeserializeObject(b, "a.bin", BIN); // ok
cout << b << endl;
uint32_t c = 321;
SerializeObject(c, "c.txt", JSON); // ok
uint32_t d;
DeserializeObject(d, "c.txt", JSON); // error
cout << b << endl;
}
I found out that the top level node in the generated JSON file is not closed. See the content of c.txt
file from the example:
{
"value0": 321
This must be incorrect behavior or I'm missing something? I don't know how to resolve this correctly. Thank you in advance for your help!
Lifetime issue can be solved much easier:
if (std::ofstream file{filename})
//file belongs to `if` scope: no need to close.
cereal::JSONOutputArchive{file}(obj);
/*Archive is rvalue and is destructed
immediately if not captured by a reference.*/
Note: since I use ofstream
instead of fstream
, the ios_base::out
flag is redundant. Similarly for input files, you can use ifstream
. The ios_base::binary
is still needed for binary files:
if (std::ofstream file{filename, std::ios_base::binary})...