Slightly related question to this one and this one.
Basically, I would like to serialize objects as they come, much like a log file, except that I want to unserialize them later. This means that I don't have all the objects initially.
From previous answers, it looks like if one keeps the same archive open, one can keep on adding more and more objects to the archive.
But how would I extract them? Do I need to look ahead and see whether eof is reached before each extraction? Should I place a linebreak into the saving routine so that I can later read the input line by line (this would probably only work with binary archives (and maybe text), as xml uses linebreaks, and maybe not even there if binary might use a linebreak occasionally)? Maybe the >> operation throws an exception if the file end is reached and I can wrap it in an infinite loop with a try catch around it?
And how would I go about it if I wanted to do so for different kinds of objects? Maybe have an enum for all objects and serialize the enum just before, and on unserializing have a switch based on the enum?
Thanks
What you're talking about is not really the point of serialization. Serialization is designed to work when the order of the writes and reads are compile-time determined. Even versioning is compile-time; you either serialize a value or not based on the runtime-version. The order is retained.
Now, you could add some tokens to the outputs, some kind of integer value that maps to class types. That is, before writing a class to the stream, you write an integer representing what that class is. Then you read it later and decide what type to serialize next based on that.
But the problem you're going to run into is that, eventually, you'll run out of content. And the serialization archives don't really have a way of saying "that's all." They're expected to be compile-time defined, so reading past the end of input is considered a user error. So processing arbitrary amounts of serialized data is not easily supported.
Again, you could write a special token to the output, something that says, "this is the end."
Here is what I did in the end. Since Nicol is right and this really is a bit of not-intended use, first one has to make sure to disable pointer tracking. Otherwise one gets spurious shared objects. Hence to begin with, loads of
BOOST_CLASS_TRACKING(yourDerivedClass,boost::serialization::track_never)
I also settled for just logging objects that derive from the same base object (you could just create an empty virtual base for this purpose). Once that is done, it is important to make sure it is seen as abstract (I made sure to have virtual destructors, and still added
BOOST_SERIALIZATION_ASSUME_ABSTRACT(yourBaseClass)
Register all derived classes with the archive after creating it (both write and read)
arMsgs.template register_type<yourDerivedClass>();
Only register final non abstract class (if A derives from B derives from C, don't register B). At least any registered class needs to have tracking disabled.
Finally add them to the archive as they come.
To reload them, rather than using a special token for end of file, which would require checking, I went for
try
{
for(;;)
{
yourBaseClass obj;
arObjs >> boost::serialization::make_nvp("Obj",obj);
//your logic
}
}
catch(boost::archive::archive_exception const& e) { }
That might catch a bit too much, so might need some extra checks but this is working for me. The advantage is that a proper shut down isn't as important, e.g. if your app crashes midway through, you can still process up to the last readable message.
I am learning boost, and I think you can use boost serialization as a log file and keep adding values using your logic. I faced the same problem, and if I'm not wrong your code was something like this :
#include <iostream>
#include <fstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
int main() {
int two=2;
for(int i=0;i<10;i++) {
std::ofstream ofs("table.txt");
boost::archive::text_oarchive om(ofs);
om << two;
two = two+30;
std::cout<<"\n"<<two;
}
return 0;
}
Here when you close the braces (braces of the loop), the serialization file closes. And you may see only one value written in table.txt , if you want to store multiple values, your code should be something like this:
#include <iostream>
#include <fstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
int main() {
int two=2;
{
std::ofstream ofs("table.txt");
boost::archive::text_oarchive om(ofs);
for(int i=0;i<10;i++) {
om << two;
two = two+30;
std::cout<<"\n"<<two;
}
}
return 0;
}
Here you can see that the braces enclosing boost::serialization::text_oarchive closes only when I'm done with serialization of the result of my logic.