Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost Serialization multiple objects

I am serializing a class with boost using binary. I'm using ios::append in order to keep appending multiple objects to this file. How do I go about retrieving all of the objects that are stored?

Here is my test class which tries a multiple serialize and retrieve them. I've comment the failure point where I don't get correct data.

using namespace std;
 class Data {
 public:
double get_latitude() const {
    return _latitude;
}

double get_longitude() const {
    return _longitude;
}

void set_latitude(double _latitude) {
    this->_latitude = _latitude;
}

void set_longitude(double _longitude) {
    this->_longitude = _longitude;
}
private:
double _latitude;
double _longitude;
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<.  Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
    ar & _latitude;
    ar & _longitude;
}
};

class DataTest: public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( DataTest);
CPPUNIT_TEST(testMultipleSaveData);
CPPUNIT_TEST_SUITE_END();

public:

void testMultipleSaveData() {
    Data data;
    data.set_latitude(1.0);
    data.set_longitude(2.0);
    saveData(data);
    Data secondData;
    secondData.set_latitude(5.0);
    secondData.set_longitude(6.0);
    saveData(secondData);
    Data returnData;
    Data return2Data;
    {
        // create and open an archive for input
        std::ifstream ifs("data.dat", ios::binary);
        boost::archive::binary_iarchive ia(ifs);
        // read class state from archive
        ia >> returnData;
        ia >> return2Data;
        // archive and stream closed when destructors are called
    }
    CPPUNIT_ASSERT_EQUAL(data.get_latitude(), returnData.get_latitude());
    CPPUNIT_ASSERT_EQUAL(data.get_longitude(), returnData.get_longitude());
    //Failure on next line
    CPPUNIT_ASSERT_EQUAL(secondData.get_latitude(), return2Data.get_latitude());
    CPPUNIT_ASSERT_EQUAL(secondData.get_longitude(), return2Data.get_longitude());
}

void saveData(Data data) {
    std::ofstream ofs("data.dat", ios::binary | ios::app);
    boost::archive::binary_oarchive oa(ofs);
    oa << data;
}

 };
 CPPUNIT_TEST_SUITE_REGISTRATION( DataTest);
like image 684
Tavis Bones Avatar asked Feb 02 '23 21:02

Tavis Bones


1 Answers

Decided to add another answer to avoid complete mess.

Your problem is that you serialize to separate instances of boost::archive::binary_oarchive. Boost Archive stores some internal info at the beginning of the file (I won't call it a header because Boost Serialization has separate header to store version number), and you receive two copies of this info, at the beginning of the file and between your Data serializations.

Boost Archive wasn't designed for such usage. Even specifying boost::archive::no_header like in:

boost::archive::text_oarchive oa(ofs, boost::archive::no_header);

doesn't help, because this option configures another header, that contains version number. You need to serialize to the same instance of Boost Archive.

like image 54
Andriy Tylychko Avatar answered Feb 05 '23 17:02

Andriy Tylychko