Serialize a derived class with constant members

Hello, I have an issue with trying to serialize const members of a derived class. I tried the solution form this link: https://stackoverflow.com/questions/50603180/serialization-of-class-with-const-members-using-boost
and will show the results with this and without.

Here is the code that I would like to work:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/void_cast_fwd.hpp>
#include <boost/serialization/binary_object.hpp>

#include <iostream>
#include <fstream>
#include <memory>
#include <sstream>
#include <vector>


class Car {
public:
    virtual char const* type() const = 0;
    virtual void printMember () const = 0;
    virtual ~Car() = default;
private:
    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive& ar, const unsigned int version) {};
};

class Audi : public Car {
public:
  Audi() {};
  Audi(const std::string owner, const int hp)
    : _owner ( owner ),
      _hp    ( hp )
  { }
  char const* type() const override { return "Audi"; }
  void printMember () const override
  {
    std::cout
      << this->type() << ":\n"
      << "owner: " << _owner
      << " hp: " << _hp
      << std::endl;
  }
private:
  const std::string  _owner; // These two lines are causing the errors. If you remove const from
  const int          _hp; // both of these lines, the code works
  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version) {
      ar & boost::serialization::base_object<Car>(*this);
      ar & _owner;
      ar & _hp;
  }
};

BOOST_CLASS_EXPORT(Audi);
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract

int main() {
  std::string save_file = "test.dat";
  std::ofstream of(save_file, std::ofstream::binary);
  std::ifstream in_f(save_file, std::ifstream::binary);
  { //saving
    std::shared_ptr<Car> audi = std::make_shared<Audi>("Wilma", 3);
    audi->printMember();

    std::stringstream strs;
    boost::archive::binary_oarchive ar(of);
    ar& audi;

    std::cout << "Count of audi:" << audi.use_count() << std::endl;

    ar << boost::serialization::make_binary_object(&audi, sizeof(audi));
  }

{ //loading
    std::shared_ptr<Car> audi; 
    std::cout << "Count of audi:" << audi.use_count() << std::endl;

    boost::archive::binary_iarchive ar(in_f);
    ar& audi;
    Audi& d = dynamic_cast<Audi &>(*audi);

    std::cout << "Count of audi:" << audi.use_count() << std::endl;
    d.printMember();
}

  return 0;
}



And here is the error:
https://paste.ofcode.org/FqQ2Mp3iuPKsVzi3kSpTcf

Here is with the help of the stackoverflow:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Audi : public Car {
public:
  Audi() {};
  Audi(const std::string owner, const int hp)
    : _owner ( owner ),
      _hp    ( hp )
  { }
  char const* type() const override { return "Audi"; }
  void printMember () const override
  {
    std::cout
      << this->type() << ":\n"
      << "owner: " << _owner
      << " hp: " << _hp
      << std::endl;
  }
private:
  const std::string  _owner;
  const int          _hp;
  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version) {
      ar & boost::serialization::base_object<Car>(*this);
      ar & _owner;
      ar & _hp;
  }
  template<class Archive>
  void load_construct_data(Archive & ar, Audi * t, const unsigned int version) {
    int _hp;
    std::string _owner;
    ar & _hp; 
    ar & _owner;
    new (t) Audi(_hp, std::move(_owner));
  }
};



And the error:

https://paste.ofcode.org/4UUqHMeGXj768urvX2h7JD

The code works without the `const` before `std::string _owner;` `int _hp;` in the private of the `Audi` class but I need them to be `const`. Does anyone have an idea how I can fix this? Any help is appreciated!
Last edited on
rtfm: https://www.boost.org/doc/libs/1_70_0/libs/serialization/doc/serialization.html#const


> And here is the error:
> https://paste.ofcode.org/FqQ2Mp3iuPKsVzi3kSpTcf
error: no matching function for call to ‘Audi::Audi()’

given line 32 of your first snip Audi() {}; that error does not refer to that code


> And the error:
> https://paste.ofcode.org/4UUqHMeGXj768urvX2h7JD
In constructor ‘Audi::Audi()’:
error: uninitialized const member in ‘const int'
note: ‘const int Audi::_hp’ should be initialized

Consider you do Audi foo;, ¿what are the values of `foo._hp' and `foo._owner'?
Hi ne555, thanks for the manual, can't believe I passed that.

On the `Audi () {}` error: I am only getting this error when _hp and _owner are defined as const in private. When I remove the const the error goes away. Do you have an idea what could cause this?
a const variable may not change its value
you are declaring a const variable and no providing a value for it
the compiler complains because the programmer quite likely made a mistake

so, initialise your variables Audi(): _hp(42), _owner("no") {}
I having been trying to solve the error but I'm still getting errors. From https://www.boost.org/doc/libs/1_70_0/libs/serialization/doc/serialization.html#const I changed the `serialize()` function to:

1
2
3
4
5
6
7
8
9
10
private:
  const std::string  _owner;
  const int          _hp;
  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version) {
      ar & boost::serialization::base_object<Car>(*this);
      ar & const_cast<Audi &>(_hp); 
      ar & const_cast<Audi &>(_owner);
  }




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
aud_seri_simple.cpp: In instantiation of ‘void Audi::serialize(Archive&, unsigned int) [with Archive = boost::archive::binary_oarchive]’:
/usr/include/boost/serialization/access.hpp:116:9:   required from ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = Audi]’
/usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = Audi]’
/usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = Audi]’
/usr/include/boost/archive/detail/oserializer.hpp:153:40:   required from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::binary_oarchive; T = Audi]’
/usr/include/boost/archive/detail/oserializer.hpp:106:1:   required from ‘class boost::archive::detail::oserializer<boost::archive::binary_oarchive, Audi>’
/usr/include/boost/archive/detail/oserializer.hpp:221:31:   [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/serialization/export.hpp:86:1:   required from ‘struct boost::archive::detail::ptr_serialization_support<boost::archive::binary_oarchive, Audi>’
/usr/include/boost/archive/detail/register_archive.hpp:25:8:   required from ‘struct boost::archive::detail::_ptr_serialization_support<boost::archive::binary_oarchive, Audi>’
/usr/include/boost/archive/binary_oarchive.hpp:57:1:   required by substitution of ‘template<class Serializable> typename boost::archive::detail::_ptr_serialization_support<boost::archive::binary_oarchive, Serializable>::type boost::archive::detail::instantiate_ptr_serialization(Serializable*, boost::archive::binary_oarchive*, boost::archive::detail::adl_tag) [with Serializable = Audi]’
/usr/include/boost/serialization/export.hpp:123:38:   required from ‘void boost::archive::detail::extra_detail::guid_initializer<T>::export_guid(mpl_::false_) const [with T = Audi; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/serialization/export.hpp:133:9:   required from ‘const boost::archive::detail::extra_detail::guid_initializer<T>& boost::archive::detail::extra_detail::guid_initializer<T>::export_guid() const [with T = Audi]’
aud_seri_simple.cpp:84:1:   required from here
aud_seri_simple.cpp:79:12: error: invalid const_cast from type ‘const int*’ to type ‘Audi*’
       ar & const_cast<Audi &>(_hp);
            ^~~~~~~~~~~~~~~~~~~~~~~
aud_seri_simple.cpp:80:12: error: invalid const_cast from type ‘const string*’ {aka ‘const std::__cxx11::basic_string<char>*’} to type ‘Audi*’
       ar & const_cast<Audi &>(_owner);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~
aud_seri_simple.cpp: In instantiation of ‘void Audi::serialize(Archive&, unsigned int) [with Archive = boost::archive::binary_iarchive]’:
/usr/include/boost/serialization/access.hpp:116:9:   required from ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = Audi]’
/usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = Audi]’
/usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = Audi]’
/usr/include/boost/archive/detail/iserializer.hpp:189:40:   required from ‘void boost::archive::detail::iserializer<Archive, T>::load_object_data(boost::archive::detail::basic_iarchive&, void*, unsigned int) const [with Archive = boost::archive::binary_iarchive; T = Audi]’
/usr/include/boost/archive/detail/iserializer.hpp:121:1:   required from ‘class boost::archive::detail::iserializer<boost::archive::binary_iarchive, Audi>’
/usr/include/boost/archive/detail/iserializer.hpp:370:31:   [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/serialization/export.hpp:86:1:   required from ‘struct boost::archive::detail::ptr_serialization_support<boost::archive::binary_iarchive, Audi>’
/usr/include/boost/archive/detail/register_archive.hpp:25:8:   required from ‘struct boost::archive::detail::_ptr_serialization_support<boost::archive::binary_iarchive, Audi>’
/usr/include/boost/archive/binary_iarchive.hpp:57:1:   required by substitution of ‘template<class Serializable> typename boost::archive::detail::_ptr_serialization_support<boost::archive::binary_iarchive, Serializable>::type boost::archive::detail::instantiate_ptr_serialization(Serializable*, boost::archive::binary_iarchive*, boost::archive::detail::adl_tag) [with Serializable = Audi]’
/usr/include/boost/serialization/export.hpp:123:38:   required from ‘void boost::archive::detail::extra_detail::guid_initializer<T>::export_guid(mpl_::false_) const [with T = Audi; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/serialization/export.hpp:133:9:   required from ‘const boost::archive::detail::extra_detail::guid_initializer<T>& boost::archive::detail::extra_detail::guid_initializer<T>::export_guid() const [with T = Audi]’
aud_seri_simple.cpp:84:1:   required from here
aud_seri_simple.cpp:79:12: error: invalid const_cast from type ‘const int*’ to type ‘Audi*’
       ar & const_cast<Audi &>(_hp);
            ^~~~~~~~~~~~~~~~~~~~~~~
aud_seri_simple.cpp:80:12: error: invalid const_cast from type ‘const string*’ {aka ‘const std::__cxx11::basic_string<char>*’} to type ‘Audi*’
       ar & const_cast<Audi &>(_owner);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~


I tried various variations of to rectify the error but I haven't had any success. Any insight is greatly appreciated!
_hp is not an Audi, _owner is not an Audi
you only need to remove the constness

1
2
 ar & const_cast<int &>(_hp); 
 ar & const_cast<std::string &>(_owner); 
Why do you want to make members const when you want to modify them later?

So instead of const_cast just remove the const in front of the variables?
marking something as `const' serves as documentation (this will not change) and the compiler actually enforces the restriction (it will complain if you try to modify it)
there is no intent to modify them later, it's just that you can't "initialise" them at declaration point
1
2
3
int n; //there is no good enough value to initialise it to
cin>>n; //besides, it will be set now
//but we not want n to change anymore 


const_cast has its uses, and serialization seems to be one of them.
1
2
int const a = 0; 
const_cast<int&>(a) = 24; // wrong 

It is undefined behavior to modify objects declared const.

http://eel.is/c++draft/dcl.type.cv#4
Last edited on
Topic archived. No new replies allowed.