c++serializationboostuint64

Unsigned long long serialization in boost


I am compiling a c++ code on a linux ubuntu with g++4.8.1 and boost 1.55.0. My program uses a class A, which has a member table which is an unsigned long long array. The same class has other members which are simple int. I am using boost to serialize my data. My code work and compile all fine, if I serialize all but the table in A.

However it does not compile if I try to serialize table. I get the following error:

/usr/local/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive; T = long long unsigned int]’:
/usr/local/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive; T = long long unsigned int]’:
/usr/local/include/boost/serialization/serialization.hpp:69:69:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive; T = long long unsigned int]’
/usr/local/include/boost/serialization/serialization.hpp:128:27:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive; T = long long unsigned int]’
/usr/local/include/boost/archive/detail/oserializer.hpp:152:5:   required from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::text_oarchive; T = long long unsigned int]’
/usr/local/include/boost/archive/detail/oserializer.hpp:101:1:   required from ‘class boost::archive::detail::oserializer<boost::archive::text_oarchive, long long unsigned int>’
/usr/local/include/boost/archive/detail/oserializer.hpp:214:5:   required from ‘boost::archive::detail::pointer_oserializer<Archive, T>::pointer_oserializer() [with Archive = boost::archive::text_oarchive; T = long long unsigned int]’
/usr/local/include/boost/serialization/singleton.hpp:106:7:   [ skipping 95 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/local/include/boost/archive/detail/oserializer.hpp:314:44:   required from ‘static void boost::archive::detail::save_non_pointer_type<Archive>::invoke(Archive&, T&) [with T = Metapop; Archive = boost::archive::text_oarchive]’
/usr/local/include/boost/archive/detail/oserializer.hpp:525:24:   required from ‘void boost::archive::save(Archive&, T&) [with Archive = boost::archive::text_oarchive; T = Metapop]’
/usr/local/include/boost/archive/detail/common_oarchive.hpp:69:40:   required from ‘void boost::archive::detail::common_oarchive<Archive>::save_override(T&, int) [with T = Metapop; Archive = boost::archive::text_oarchive]’
/usr/local/include/boost/archive/basic_text_oarchive.hpp:80:9:   required from ‘void boost::archive::basic_text_oarchive<Archive>::save_override(T&, int) [with T = Metapop; Archive = boost::archive::text_oarchive]’
/usr/local/include/boost/archive/detail/interface_oarchive.hpp:63:9:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = Metapop; Archive = boost::archive::text_oarchive]’ 
simulation.cpp:1403:9:   required from here
/usr/local/include/boost/serialization/access.hpp:118:9: error: request for member ‘serialize’ in ‘t’, which is of non-class type ‘long long unsigned int’
     t.serialize(ar, file_version);
     ^

I have read aroud that if I used vectors or/and an other data type it would work. However it is critical for me (for speed) to use a raw array of unsigned long long. Any idea ?

Thnaks a lot for you help !


Solution

  • Serializing unsigned long long arrays works for me using gcc 4.7.2 with boost 1.49, gcc 4.2.1 with boost 1.55, and clang 3.4 with boost 1.55:

    #include <sstream>
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/serialization/access.hpp>
    #include <boost/version.hpp>
    
    struct Foo {
       unsigned long long bar[3];
    
       template<class Archive>
       void serialize(Archive& ar, const unsigned int /*version*/) {
          ar & bar;
       }
    };
    
    std::ostream& operator<<(std::ostream& os, const Foo& foo) {
       return os << foo.bar[0] << ' ' << foo.bar[1] << ' ' << foo.bar[2];
    }
    
    int main() {
       std::cout << "Boost version " << BOOST_LIB_VERSION << '\n';
    
       Foo before;
       before.bar[0] = 0;
       before.bar[1] = 1;
       before.bar[2] = 2;
    
       std::cout << "before: " << before << '\n';
    
       std::ostringstream os;
       {
          boost::archive::text_oarchive oa(os);
          oa << before;
       }
    
       Foo after;
       {
          std::istringstream is(os.str());
          boost::archive::text_iarchive ia(is);
          ia >> after;
       }
    
       std::cout << "after: " << after << '\n';
    
       return 0;
    }
    

    Here's gcc 4.8 with boost 1.55 on Coliru, also works.

    If you are using a pointer to an allocated array, then I think that is your problem. I don't believe you can serialize a bare pointer to a primitive, and I'm sure you can't serialize a bare pointer to an array of primitives because there is no way for serialization to know how many elements a pointer points to.

    I would use a std::vector over an allocated array because there is no speed disadvantage in doing so. However, if you really want to allocate your own array then you can serialize it with the boost::serialization::make_array() wrapper like this:

    #include <iostream>
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/serialization/access.hpp>
    #include <boost/serialization/array.hpp>
    
    struct Foo {
       size_t dataSize;
       unsigned long long *data;
    
       Foo()
          : dataSize(3)
          , data(new unsigned long long[dataSize]) {
       }
    
       ~Foo() {
          delete[] data;
       }
    
       // TODO: Production code should disallow default copy constructor
       // and assignment operator.
    
       template<class Archive>
       void serialize(Archive& ar, const unsigned int /*version*/) {
          ar & dataSize;
          ar & boost::serialization::make_array(data, dataSize);
       }
    };
    
    int main() {
       Foo foo;
       foo.data[0] = 0;
       foo.data[1] = 1;
       foo.data[2] = 2;
    
       boost::archive::text_oarchive oa(std::cout);
       oa << foo;
    
       return 0;
    }
    

    It turns out that this question was not about unsigned long long at all, but is essentially a duplicate of boost serialization, deserialization of raw C arrays.