In short, combining a class implementation of serialize() with load/save_construct_data as described in the docs writes and reads data twice. Varying the pattern can produce exceptions. My solution is to implement serialize() as a no-op and provide paired load/save_construct_data() functions. Is that actually a solution? Is there a better way?
The code at the bottom of this message yields Microsoft C++ exception: boost::archive::archive_exception at memory location 0x000000B8189AC300. When attempting to read in what was just written out. Debugging shows that code attempts to read in the object twice, first in the class-specific load_construct_data function I wrote, and then again in the instance method A::serialize. Since the save operation only wrote it out once, there is nothing, or at least nothing expected, to read and things go badly. The documentation (https://www.boost.org/doc/libs/1_76_0/libs/serialization/doc/serialization.html#constructors) says "If there is no such default constructor, the function templates load_construct_data and perhaps save_construct_data will have to be overridden." "perhaps" seems to imply that it is not essential to do so, and since the lack of a default constructor only matters when materializing an object I only wrote a load_construct_data function. The example in the documentation does show both a save_construct_data and a load_construct_data function and if I uncomment save_construct_data in the code below, it runs without error and reconstructs the object. HOWEVER, this only works because the data are written out twice, and then read in twice. I think the problem is that TestBed.exe!boost::archive::detail::pointer_iserializer<boost::archive::text_iarchive,A>::load_object_ptr(boost::archive::detail::basic_iarchive & ar, void * t, const unsigned int file_version) Line 340 at J:\Programs\boost_1_76_0\boost\archive\detail\iserializer.hpp(340) first materializes the object and then--after it is already constructed--passes it off to ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t)); at the end, triggering the call to A::serialize and the 2nd read from the archive. For now I have kept the save_construct_data function and made A::serialize a no-op; the serialization framework seem to require that it exist. This appears to work. Boost 1.76 Microsoft Visual Studio Community 2019 v16.10.1 with Language Level /std:c++latest. // TestBed.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include <iostream> #include <fstream> #include <string> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> class A : boost::noncopyable { public: int a1; A(const int x1) : a1(x1) {}; virtual ~A() {}; template<class Archive> void serialize(Archive& ar, const unsigned int version) { ar& a1; }; }; namespace boost { namespace serialization { #if 0 template<class Archive> void save_construct_data(Archive& ar, const A* pa, const unsigned int version) { ar& pa->a1; }; #endif template<class Archive> inline void load_construct_data(Archive& ar, A* pa, const unsigned int file_version) { int x1; ar >> x1; ::new(pa)A(x1); } } } /* these are separate functions partly so RAII will close files*/ void write_out(const std::string& fpath, const A& a) { std::ofstream ofs(fpath); boost::archive::text_oarchive oa(ofs); oa << &a; } A* read_in(const std::string& fpath) { A* pa; std::ifstream ifs(fpath); boost::archive::text_iarchive ia(ifs); ia >> pa; return pa; } int main(int argc, char** argv) { const std::string fname("test.srl"); A a(810); write_out(fname, a); A* aa = read_in(fname); std::cout << "A(" << aa->a1 << std::endl; return 0; } _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org https://lists.boost.org/mailman/listinfo.cgi/boost-users