
Robert Ramey <ramey <at> rrsd.com> writes:
-----------------------------------------
* If one program writes archives like this:
ar & vec; // vec is a std::vector<char>
, it is then impossible to reliably load that archive in another program, unless one is aware of the entire compile-time content of the first program.
Nope. The only time a problem can occur if one does
ar & vec; // vec is a std::vector<char>
In the saving program and
ar & p_vec; // vec is a * std::vector<char>
in the loading progam.
Robert, that's manifestly incorrect. I have appended 3 well-formed programs, A1, A2, and B, to this post. B can read archives from A1, but it *cannot* read archives from A2. If you don't believe me, then please run the programs yourself. The only difference between A1 and A2 is compile-time instantiation, of code that is never executed.
Making matters worse, the archive
format change is compatibility- breaking.
Only for collections of primitives.
So we do agree that compatibility does break, due to compile-time instantiation.
I would use "concievable" rather than "likely". In fact, I can't think of any real program where this could occur without there being some other error that would also prevent this program from functioning.
Do you consider there to be any errors in either A1, A2 or B? If you were to implement a generic IPC marshalling layer, you would end up with the kind of code that A1, A2, and B contain. IPC serialization is a bit different from file-based serialization, in that serialization and deserialization generally take place in different programs. Another wrinkle in IPC serialization, is that one program may contain only serialization code for a type T (and not deserialization), while another program may contain only deserialization code for type T (and not serialization). If that makes the programs ill-formed in your view, then I guess one would have to conclude that B.Ser. is not an appropriate choice for IPC applications. Regards, Jarl ---------------------------------- // A1 #include <fstream> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/vector.hpp> int main() { std::vector<char> vec(25, 'A'); std::ofstream fout("A.txt"); boost::archive::text_oarchive(fout) & vec; return 0; } ---------------------------------- // A2 #include <fstream> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/vector.hpp> template<typename Archive> struct X { template<typename T> void operator<<(const T &t) { Archive &archive = (*(Archive *) NULL); archive << t; } template<typename T> void operator>>(T &t) { Archive &archive = (*(Archive *) NULL); archive >> t; } }; // This function is instantiated by the compiler, but never executed. void dummy() { typedef boost::archive::text_iarchive IArchive; typedef boost::archive::text_oarchive OArchive; std::vector<char> *pt = NULL; X<OArchive> & oar = * (X<OArchive> *) NULL; oar << pt; X<IArchive> & iar = * (X<IArchive> *) NULL; iar >> pt; } int main() { std::vector<char> vec(25, 'A'); std::ofstream fout("A.txt"); boost::archive::text_oarchive(fout) & vec; return 0; } ---------------------------------- // B #include <fstream> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/vector.hpp> int main() { std::vector<char> vec; std::ifstream fin("A.txt"); // If A1 produced the archive, this line succeeds. // If A2 produced the archive, this line will silently fail. boost::archive::text_iarchive(fin) & vec; return 0; } ----------------------------------