So I'm building a simulated file-system in C++ to study the language better and maybe some system level programming. Im using Boost::Serialization to save the state of the file system when the user exits, but I'm having trouble in saving/loading my classes. Here is my base class:
enum filetype { FSFILE, FSDIRECTORY, ROOT };
class FileObject {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int) {
ar & BOOST_SERIALIZATION_NVP(name);
ar & BOOST_SERIALIZATION_NVP(date_of_creation);
ar & BOOST_SERIALIZATION_NVP(type);
}
protected:
std::string name;
std::string date_of_creation;
filetype type;
Here is my first derived class that will be basically a .txt file in the system:
class File : public FileObject {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(FileObject);
ar & BOOST_SERIALIZATION_NVP(content);
ar & BOOST_SERIALIZATION_NVP(size);
}
protected:
std::string content;
int size;
And finally here is the Directory class that will act as the directory that holds files and/or other directories:
class Directory : public FileObject {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(FileObject);
ar & BOOST_SERIALIZATION_NVP(num_of_contents);
ar & BOOST_SERIALIZATION_NVP(size_of_contents);
for (auto it = this->contents.begin(); it != this->contents.end(); it++) {
ar & BOOST_SERIALIZATION_NVP(it->second);
}
}
protected:
int num_of_contents;
int size_of_contents;
public:
std::unordered_map<std::string, FileObject *> contents;
In my main.cc file I have 2 functions, one for saving and one for loading
void save_state(const Directory &s, const char * filename){
// make an archive
std::ofstream ofs(filename);
assert(ofs.good());
boost::archive::xml_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(s);
}
void
restore_state(Directory &s, const char * filename)
{
// open the archive
std::ifstream ifs(filename);
assert(ifs.good());
boost::archive::xml_iarchive ia(ifs);
ia >> BOOST_SERIALIZATION_NVP(s);
}
And finally here is the rest main.cc file that creates some files and dirs and saves/loads for testing purposes :
int main() {
char c;
scanf("%c", &c);
std::string filename(boost::archive::tmpdir());
filename += "/demo_save.xml";
if (c == 's') {
File file("test_file1", filetype::FSFILE);
File file2("test_file2", filetype::FSFILE);
File file3("test_file3", filetype::FSFILE);
File file4("test_file4", filetype::FSFILE);
Directory dir("test_dir1", filetype::FSDIRECTORY);
Directory dir2("test_dir2", filetype::FSDIRECTORY);
dir.insertContent(file.getName(), &file);
dir.insertContent(file2.getName(), &file2);
dir2.insertContent(file3.getName(), &file3);
dir2.insertContent(file4.getName(), &file4);
dir.insertContent(dir2.getName(), &dir2);
save_state(dir, filename.c_str());
}
Directory newd;
if (c == 'l') {
restore_state(newd, filename.c_str());
for (auto it = newd.contents.begin(); it != newd.contents.end(); it++) {
if (it->second->getType() == filetype::FSFILE) {
std::cout << it->first << std::endl;
}
else if (it->second->getType() == filetype::FSDIRECTORY) {
for (auto jt = ((Directory *)it->second)->contents.begin(); jt != ((Directory *)it->second)->contents.end(); jt++) {
std::cout << jt->second->getName() << std::endl;
}
}
}
}
return 0;
}
The programm compiles fine but i get seg fault in the second loop. And from reading the .xml file, the files inside the dir2 dont get properly serialized.
Are my classes and functions correct? Is this the correct way to serialize an unordered_map that holds pointers to other classes?
As others have pointed out you have ownership issues. You can serialize pointers but deserializing will result in memory leaks.
Instead, make the pointers owned. I will use
unique_ptrto manage that instead of writing lots of code to manage the lifetimes correctly.Then, you must make sure the hierarchy is virtual, by at least adding
I've elected to make the
FileObjectstreamable by also supplying aprintvirtual method.Lastly, register the types, or mark them abstract as appropriate:
Full Demo
Live On Coliru
Prints
And the xml contains: