boost serialization: save_construct_data not calle

2019-08-09 10:19发布

问题:

I'm using boost to serialize object without a default constructor, however I get a weird issue : save_construct_data is not being called !

Bellow a sample program that reproduce this problem:

main.cpp

#include <vector>
#include <iostream>
#include "Test.h"

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

int main()
{
    using T = float;
    walid::Test<T> instance ( 2, {2.3f, -0.5f} ) ;

    std::ofstream ofs ( "data" );
    boost::archive::text_oarchive oa ( ofs );    
    oa << instance;   
}

Test.h

#ifndef __Test_HEADER__
#define __Test_HEADER__

#include <list>
#include <vector>
#include <iostream>
#include <initializer_list>

namespace walid
{ 
    template<typename T>
    class Test
    {
      public:
        std::vector<T> elements;
    int in_dim ;

    Test(int input_dim, std::initializer_list<T> elem)
    {
      in_dim = input_dim;
      elements = std::vector<T>(elem);
    }
    void start(){};
    void stop(){};
    };
}

#include "Test_serialization.inl"

#endif

and finally Test_serialization.inl

namespace boost {
namespace serialization {

    template<class Archive, class T>
    inline void serialize(Archive & ar, walid::Test<T>& t, const unsigned int version)
    {
      std::cout<<"serialize Test ..."<<std::endl;
    }

    template<class Archive, class T>
    inline void save_construct_data ( Archive & ar, const walid::Test<T>* t, const unsigned int version )
    {
        std::cout<<"call save_construct_data Test ..."<<std::endl;

    }

    template<class Archive, class T>
    inline void load_construct_data ( Archive & ar, walid::Test<T>* t, const unsigned int version )
    {
        std::cout<<"call load_construct_data Test ..."<<std::endl;
        ::new ( t ) walid::Test<T> ( 2, {2.3f, -0.5f} ) ;
    }
}
}

this code is supposed to print :

serialize Test ... 
call save_construct_data Test ...

but it is only printing serialize Test ... (save_construct_data is not called)

Am I missing something ?

Thanks for your help.

回答1:

The assumption appears to be that you are constructing walid::Test<T>.

However, if you look closely, you will realize that you don't actually construct anything.

By design Boost Serialization (de)serializes (into) lvalues. The only place where construction is required during de-serialization is when serializing dynamically allocated objects.

You can convince yourself by changing the storage of the instance to e.g. shared_ptr:

Live On Coliru

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

#include <boost/shared_ptr.hpp>

int main()
{
    using T = float;
    using Test = walid::Test<T>;

    {
        boost::shared_ptr<Test> shared_instance(new Test(2, {2.3f, -0.5f}));

        std::ofstream ofs("data");
        boost::archive::text_oarchive oa(ofs);
        oa << shared_instance;
    }

    {
        boost::shared_ptr<Test> deserialized;

        std::ifstream ifs("data");
        boost::archive::text_iarchive ia(ifs);
        ia >> deserialized;
    }
}

Prints

call save_construct_data Test ...
serialize Test ...
call load_construct_data Test ...
serialize Test ...