Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#12321 closed Bugs (fixed)

save for boost::optional doesn't call save_construct_data but load calls load_construct_data

Reported by: Oleg Burchakov <burchakov.oleg@…> Owned by: Robert Ramey
Milestone: To Be Determined Component: serialization
Version: Boost 1.61.0 Severity: Problem
Keywords: Cc:

Description

$ cat main.cpp

#include <stdexcept>
#include <iostream>
#include <sstream>

#include <boost/optional.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/optional.hpp>

struct Foo
{
    Foo(int aBar) :
        mBar(aBar)
    {
        if (mBar > 10)
        {
            throw std::logic_error("too big bar");
        }
    }
    int bar() const
    {
        return mBar;
    }
private:
    int mBar;
};


namespace boost {
namespace serialization {

template<class Archive>
inline void serialize(Archive & ar, Foo& foo, const unsigned int /*version*/)
{
    std::cout << __FUNCTION__ << " called" << std::endl;
}

template<class Archive>
inline void save_construct_data(Archive & ar, const Foo* foo, const unsigned int /*version*/)
{
    std::cout << __FUNCTION__ << " called" << std::endl;
    ar << foo->bar();
}


template<class Archive>
inline void load_construct_data(Archive & ar, Foo* foo, const unsigned int /*version*/)
{
    std::cout << __FUNCTION__ << " called" << std::endl;
    int bar;
    ar >> bar;
    ::new(foo) Foo(bar);
}

} // serialization
} // boost


int main()
{
    boost::optional<Foo> oldFoo = Foo(10);
    std::ostringstream outStream;
    boost::archive::text_oarchive outArchive(outStream);
    outArchive & oldFoo;

    boost::optional<Foo> newFoo;
    std::istringstream inStream(outStream.str());
    boost::archive::text_iarchive inArchive(inStream);
    inArchive & newFoo;
}

$ clang++ -I include -L lib -l boost_serialization --std=c++11 main.cpp

$ LD_LIBRARY_PATH=lib ./a.out serialize called load_construct_data called terminate called after throwing an instance of 'boost::archive::archive_exception'

what(): input stream error

Aborted (core dumped)

Change History (4)

comment:1 by anonymous, 6 years ago

I unfortunately ran into the same issue. When only serializing pointers the issue can be work arounded.

comment:2 by Robert Ramey, 6 years ago

OK - this is tricky problem. I'll take a look at it.

comment:3 by Robert Ramey, 6 years ago

Resolution: fixed
Status: newclosed

I believe I have fixed this in a definitive way. I've checked it in to the develop branch. This is too late for boost 1.63 but will come out in next release

comment:4 by Robert Ramey, 6 years ago

I had fixed your example and checked it in. But upon doing more testing I concluded that my "fix" would just break something else. Spending a lot more time on this convinced me that the root cause of the problem is the serialization of a type which out a default constructor. The library as currently constituted really can't do that - this is not due to the usage of "optional" it's a general limitation. Maybe if I made the library again I might address this limitation. Or maybe I tried originally but just accepted the limitation (without documenting it). So I'm going to make a few changes.

a) fix it (again!) so that the test works. This will make your case fail

b) update the documentation to clarify this point. There is a workaround. If a class has no default constructor it CAN be serialized through a pointer while overloading save/load construct data.

c) use the boost type trait "has_default_constructor" to trap violations of tis rule and point to an explanation.

Sorry you'll have to work around this.

Robert Ramey

Note: See TracTickets for help on using tickets.