c++boost-serialization

Input stream error with boost serialization


I am trying to load serialized content and I have been unable to solve the issue. I have boiled it down to a specific line of code. I tried to minimize the code as best as possible but also show some debugging. The class loadAudi is only there to illustrate where the error is coming from and serves only the purpose of helping debugging the problem. The line ar& audi in loadAudi is what is causing the error. In the "real" code, the ar& audi right after boost::archive::binary_iarchive ar(in_f); is what is causing the problem. Here is the code (complete output is at the bottom):

#include <armadillo>

#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 Engine
{
public:
    Engine () {}
    Engine (const int cyl) : _cyl ( cyl ) {}
    int getCyl () const { return _cyl; }

private:
    int _cyl;

    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive& ar, const unsigned int version) {
    ar & _cyl;
    }
};

class Car {
public:
    virtual char const* type() const = 0;
    virtual void printMember () const = 0;
    virtual void save (const std::string file) const { std::cout << "file" << std::endl; };

    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 std::enable_shared_from_this<Car> {
public:

Audi() {};
Audi(const std::string owner, const int hp,const unsigned int cyl)
    : _owner ( owner ),
    _hp    ( hp ),
    _eng          ( std::make_shared<Engine>(cyl) )
{ }

char const* type() const override { return "Audi"; }

void printMember () const override
{
    std::cout
    << this->type() << ":\n"
    << "owner: " << _owner
    << " hp: " << _hp
    << " engine: " << _eng->getCyl()
    << std::endl;
}
void save (const std::string file) const {
    std::ofstream of(file, std::ofstream::binary);
    std::stringstream strs;
    boost::archive::binary_oarchive ar(of);
    std::shared_ptr<const Car> audi = shared_from_this();
    boost::serialization::make_binary_object(&audi, sizeof(audi));
}

private:
std::string  _owner;
int          _hp;
std::shared_ptr<Engine> _eng;

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;
    ar & _eng;
}
};

Audi& loadAudi (const std::string file_name) {
std::cout << "Loading " << file_name << std::endl;
std::ifstream in_f(file_name, std::ifstream::binary);

std::cout << "1" << std::endl;
std::shared_ptr<Car> audi; //= std::make_unique<Audi>();

std::cout << "2" << std::endl;
boost::archive::binary_iarchive ar(in_f);

std::cout << "3" << std::endl;
ar& audi;

std::cout << "4" << std::endl;
return dynamic_cast<Audi &>(*audi);
};

BOOST_CLASS_EXPORT(Audi);
BOOST_CLASS_EXPORT(Engine);
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);
{
    std::shared_ptr<Car> audi = std::make_shared<Audi>("Wilma", 3, 16);
    audi->printMember();

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

    // audi_save_dir = strs.str();
    std::cout << "Count of audi:" << audi.use_count() << std::endl;

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


{
    std::shared_ptr<Car> audi; //= std::make_unique<Audi>();
    std::cout << "Deserialize: Count of audi:" << audi.use_count() << std::endl;

    //std::stringstream strs(f);
    boost::archive::binary_iarchive ar(in_f);
    ar& audi;
    Audi& d = dynamic_cast<Audi &>(*audi);

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


std::shared_ptr<Car> audi = std::make_shared<Audi>("Daniel", 200, 8);
audi->printMember();

std::string test_dat = "my-new-audi.dat";
audi->save(test_dat);
Audi& d =  loadAudi(test_dat);
d.printMember();

return 0;
}

And the output:

Audi:
owner: Wilma hp: 3 engine: 16
Count of audi:1
Deserialize: Count of audi:0
Deserialize: Count of audi:2
Print Audi:
Audi:
owner: Wilma hp: 3 engine: 16
Audi:
owner: Daniel hp: 200 engine: 8
Loading my-new-audi.dat
1
2
3
terminate called after throwing an instance of 'boost::archive::archive_exception'
what():  input stream error
[2]    29888 abort      ./a.out

I would appreciate any help!


Solution

  • 2 issues here.

    1. You did not serialize audi object inside save method by ar << audi call.
    2. You return a reference to audi object from loadAudi function. This object you are referencing to is destroyed right after you exit the function.