Boost logo

Boost Users :

From: Boylan, Ross (Ross.Boylan_at_[hidden])
Date: 2021-06-11 00:17:29


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 list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net