I'm trying to use the boost serialization library to serialize a class. The serializing works just fine but when I try to read the contents that were wrote to a file a get an "input error" exception.
I read the Documentation of the boost serialization library and came up with the (1) to understand how to serialize and deserialize a class with non-default constructors. I was trying to keep as close to the example from the documentation as I could.
I tried removing ar & name
from the serialize method (which the documentation example did) in the Book class which also resulted in an input stream error.
When debugging I recognized that the exception gets thrown in the load _access
class in the load_primitive` function.
#include <fstream>
#include <filesystem>
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class Book
{
private:
std::string name;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int file_version)
{
ar & name;
}
public:
Book(std::string name): name(name) {}
};
namespace boost {
namespace serialization {
template<class Archive>
inline void save_construct_data(Archive& ar, Book* book, const unsigned int file_version)
{
ar << book->name;
}
template<class Archive>
inline void load_construct_data(Archive& ar, Book* book, const unsigned int file_version)
{
std::string name;
ar >> name;
::new(book)Book(name);
}
}
}
int main()
{
Book book("Harry Potter");
std::ofstream ofs("Book.txt");
boost::archive::text_oarchive oa(ofs);
oa << &book;
ofs.close();
Book* read;
std::ifstream ifs("Book.txt", std::ios::binary);
boost::archive::text_iarchive ia(ifs);
ia >> read;
ifs.close();
}
I am getting the following error
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): input stream error
Thanks in advance for any awnser. Felix
save_construct_data()
and load_construct_data()
should work together, but in your code save_construct_data()
is never called. This happens because it has incorrect signature: Book*
should be const Book*
.
You then get a stream error because serialization and deserialization are inconsistent with each other – serialization writes Book::name
once, in serialize()
, but deserialization tries to read it twice, in load_construct_data()
and in serialize()
.
Complete working example (main()
is unchanged, except removing std::ios::binary
):
class Book {
friend class boost::serialization::access;
private:
std::string name;
template<class Archive>
void serialize(Archive&, unsigned int) { }
template<class Archive>
friend void save_construct_data(Archive& ar, const Book* book, unsigned int) {
ar << book->name;
}
template<class Archive>
friend void load_construct_data(Archive& ar, Book* book, unsigned int) {
std::string name;
ar >> name;
::new(book) Book(std::move(name));
}
public:
Book(std::string name): name(std::move(name)) { }
};
I declared save_construct_data()
as a friend
inside the class to simplify code. For some reason, if it is defined in boost::serialization
namespace, you need to add a friend
declaration for that function in addition to befriending boost::serialization::access
. This is not mentioned in the documentation, but code doesn't compile without that friend
declaration.