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

Reply via email to