I am using boost to (de)serialize some classes. All is well except for a class which has astd::vector<Artefact*> member (see below for definitions). I have problems with vectors of pointers.
I can (de)serialize single instances of class Artefact perfectly.
I cannot serialize a class which has a vector of pointers to class Artefact.
The boost error when I try to do so is:
"unregistered class - derived class not registered or exported"
I am getting some output. Archive file:
22 serialization::archive 19 1 0
0 1 0
1 1 0
2 0 0 66 0
Class Definitions
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
...
class Tag {
public:
bool tag = false;
};
class Artefact : public Tag {
public:
std::vector<enjyn_Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<enjyn_Texture*> textures;
glm::vec3 position{ 0.0f };
glm::vec3 scale{ 1.0f };
glm::vec3 rotation{ 0.0f, 1.0f, 0.0f };
float rotation_degrees{ 0.0f };
glm::vec4 colour{ 1.0f, 1.0f, 1.0f, 1.0f };
...
std::vector<Artefact> artefacts; // note, no problem serializing std::vector<Artefact> here
...
};
//Mainly static data and function members
class State {
public:
...
static std::map<std::string, bool> state;
...
}
class Event {
public:
...
virtual void OnMouseFocus(); //Lots of virtual data members like this one here
..
}
//Large class with lots of data and function members.
class Enjyn : public Event, public State {
public:
...
std::vector<Artefact*> artefacts; // I believe this is the problem member
...
}
Free Non-Intrusive (De)Serialization Functions
I have non-intrusive free serialize functions for all classes I want to archive including serialize functions for all base classes and non built in data members).
The serialize function below (de)serializes perfectly for single instances of Artefact:
#include <boost/serialization/export.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
...
void serialize(Archive& ar, Artefact& a, const unsigned int version) {
//ar.template register_type<Artefact>(); ; commented as classes exported see below
ar& boost::serialization::base_object<enjyn_Tag>(a);
ar& a.vertices;
ar& a.indices;
ar& a.textures;
ar& a.position;
ar& a.scale;
ar& a.rotation;
ar& a.rotation_degrees;
ar& a.colour;
ar& a.aabb;
ar& a.bsphere;
ar& a.tex_offset_x;
ar& a.tex_offset_y;
ar& a.tex_scale_x;
ar& a.tex_scale_y;
ar& a.name;
ar& a.artefacts; //works fine for vector of non-pointer vector of Artefact.
}
However when I try to archive an object with a std::vector<Artefact*>, I get:
"unregistered class - derived class not registered or exported"
void serialize(Archive& ar, Enjyn& e, const unsigned int version)
{
//ar.template register_type<enjyn>(); commented as classes exported see below:
ar& boost::serialization::base_object<Event>(e); // not sure whether this is necessary, no tracking requried of base classes.
ar& boost::serialization::base_object<State>(e);
ar.template register_type<Artefact>();
...
ar& e.artefacts; //This is a std::vector<Artefact*> which I cant archive
//if i remove this and add include any 'normal' non-pointer
//built in types the serialization appears to work perfectly.
...
}
Serializing Program Functions
I am serializing single instances of Artefact objects perfectly like this:
if (e.primary_artefact) { //primary_artefact is a pointer to an instance of Artefact
try {
std::string filepath = "test_filename";
std::ofstream o(filepath);
{
boost::archive::text_oarchive oa(o);
oa << *e.primary_artefact;
}
}
catch (std::ifstream::failure e) {
std::cerr << "ERROR:IFSTREAM: " << e.what() << std::endl;
}
catch (boost::archive::archive_exception e) {
std::cerr << "ERROR:BOOST SERIALISATION: " << e.what() << std::endl;
}
}
Attempting to serialize class Enjyn using this function creates error if I include Enjyn.artefacts (std::vector<Artefact*>) in the serialize function:
void serialize_enjyn(enjyn& e, std::string& name)
try {
std::string filepath = name;
std::ofstream o(filepath);
{
boost::archive::text_oarchive oa(o);
oa << e;
}
}
catch (std::ifstream::failure e) {
std::cerr << "ERROR:IFSTREAM: " << e.what() << std::endl;
}
catch (boost::archive::archive_exception e) {
std::cerr << "ERROR:BOOST SERIALISATION: " << e.what() << std::endl;
}
}
I went mad and exported GUIDS for all types in my main program file so all relevant types could be tracked within the archive. Not that this is particularly necessary. Only tracking of '''class Artefact''' is required.
#include <boost/serialization/export.hpp>
BOOST_CLASS_EXPORT_GUID(glm::vec2, "vec2")
BOOST_CLASS_EXPORT_GUID(glm::vec3, "vec3")
BOOST_CLASS_EXPORT_GUID(glm::vec4, "vec4")
BOOST_CLASS_EXPORT_GUID(Artefact, "enjyn_Artefact")
BOOST_CLASS_EXPORT_GUID(Vertex, "enjyn_Vertex")
BOOST_CLASS_EXPORT_GUID(Texture, "enjyn_Texture")
BOOST_CLASS_EXPORT_GUID(Tag, "enjyn_Tag")
BOOST_CLASS_EXPORT_GUID(State, "enjyn_State")
BOOST_CLASS_EXPORT_GUID(Event, "enjyn_event")
BOOST_CLASS_EXPORT_GUID(Enjyn, "enjyn")
int main(int argc, char* argv[]){
Discussion
Note, the Artefact object is used as a base for other classes. I have not registered those classes or written serialization functions for them as Artefact has no virtual functions, I am trying to serialize Artefact directly (though indirectly also via pointers), and the documentation for registration states:
It turns out that the kind of object serialized depends upon whether the base class (base in this case) is polymophic or not. If base is not polymorphic, that is if it has no virtual functions, then an object of the type base will be serialized. Information in any derived classes will be lost. If this is what is desired (it usually isn't) then no other effort is required.
The problem appears to be with the member std::vector<Artefact*> artefact in Enjyn. When I remove this from the serialize function for Enjyn, Enjyn serializes perfectly. I am obviously missing something fundemental to do with:
pointers, std::vector, and derived types and base classes from the boost documentation.
Please help!
