Как использовать Boost Serialization с производными классами в C ++? - PullRequest
3 голосов
/ 23 августа 2011

Я пытаюсь использовать функцию сериализации Boost для сериализации производного класса. Мой базовый класс не имеет разных членов данных, поэтому производный класс просто имеет эту функцию serialize ():

template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
    ar & boost::serialization::base_object<Car>(*this);
}

Тогда базовый класс имеет эту функцию serialize ():

template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
    ar & color;
    ar & miles;
    ar & model;
    ar & doors;
}

Добавление этого в базовый класс не имеет значения:

BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car)

Программа компилируется просто отлично. Функция main () генерирует некоторые фиктивные данные, печатает их на стандартный вывод, а затем сохраняет их с расширенной сериализацией. Затем он пытается прочитать данные из файла и распечатать результаты. Он прекрасно сохраняет данные, и я могу открыть файлы данных и подтвердить, что данные действительно присутствуют.

Однако при перестройке производного класса (а также при перестроении экземпляра базового класса) происходит сбой в начале функции serialize () для базового класса. Какие-нибудь мысли? Я думаю, что я все сделал правильно из примера, представленного на сайте Boost. Заранее спасибо. Кроме того, я использую GCC 4 в Mac OS X и последнюю версию библиотеки Boost (из исходных текстов), и пример программы отлично работает с boost, когда не имеет дело с наследованием.

Обновление: Я получаю ту же проблему при попытке запустить пример кода в документации Boost http://www.boost.org/doc/libs/1_42_0/libs/serialization/doc/tutorial.html#derivedclasses:

class bus_stop_corner: public bus_stop {
friend class boost::serialization::access;
friend ostream& operator<<(ostream &out, const bus_stop_corner &bsc);
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
    // serialize base class information
    ar & boost::serialization::base_object<bus_stop>(*this); // Fails here
    ar & street1;
    ar & street2;
}
string street1;
string street2;
virtual string description() const {
    return street1 + " and " + street2;
}
public:
bus_stop_corner(){}
bus_stop_corner(const gps_position & lat_, const gps_position & long_, const string & s1_, const string & s2_): bus_stop(lat_, long_), street1(s1_), street2(s2_) {}
};

Для ar & boost::serialization::base_object<bus_stop>(*this); GDB говорит EXC_BAD_ACCESS.

Derived.h

#ifndef BoostSerialization_Derived_h
#define BoostSerialization_Derived_h
// This is pretty much the same code from the Boost Serialization documentation!
#include <boost/serialization/access.hpp>
#include <boost/serialization/base_object.hpp>
#include <iostream>
#include <string>
using namespace std;

class gps_position {
public:
    int degrees;
    int minutes;
    float seconds;
    gps_position(){};
    gps_position(int d, int m, float s):degrees(d), minutes(m), seconds(s) {}
    gps_position(const gps_position &gp) {this->degrees = gp.degrees; this->minutes = gp.minutes; this->seconds = gp.seconds;}
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) {
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
};

class bus_stop {
    friend class boost::serialization::access;
    friend ostream& operator<<(ostream &out, const bus_stop &bsc);
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) {
        ar & latitude;
        ar & longitude;
    }
protected:
    gps_position latitude;
    gps_position longitude;
    bus_stop(const gps_position & lat_, const gps_position & long_): latitude(lat_),   longitude(long_) {}
public:
    bus_stop(){}
    bus_stop(const bus_stop &bs) {this->latitude = bs.latitude; this->longitude = bs.longitude;}
    // See item # 14 in Effective C++ by Scott Meyers.
    // re non-virtual destructors in base classes.
    virtual ~bus_stop(){}
};

class bus_stop_corner: public bus_stop {
    friend class boost::serialization::access;
    friend ostream& operator<<(ostream &out, const bus_stop_corner &bsc);
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) {
        // serialize base class information
        ar & boost::serialization::base_object<bus_stop>(*this);
        ar & street1;
        ar & street2;
    }
    string street1;
    string street2;
    virtual string description() const {
        return street1 + " and " + street2;
    }
public:
    bus_stop_corner(){}
    bus_stop_corner(const bus_stop_corner &bsc) {this->street1 = bsc.street1; this->street2 = bsc.street2; this->latitude = bsc.latitude; this->longitude = bsc.longitude;}
    bus_stop_corner(const gps_position & lat_, const gps_position & long_, const string & s1_, const string & s2_): bus_stop(lat_, long_), street1(s1_), street2(s2_) {}
};

ostream& operator<<(ostream &out, const gps_position &gps);
ostream& operator<<(ostream &out, const bus_stop &bsc);
ostream& operator<<(ostream &out, const bus_stop_corner &bsc);

void derivedClassTest();
void derivedClassSave();
void derivedClassLoad();
#endif

Derived.cpp

#include "Derived.h"
#include "GenericSerializer.h"

ostream& operator<<(ostream &out, const gps_position &gps) {
    out << gps.degrees << " degrees " << gps.minutes << "\" " << gps.seconds << "'";
    return out;
}

ostream& operator<<(ostream &out, const bus_stop &bsc) {
    out << "Bus stop at " << bsc.latitude << " and " << bsc.longitude;
    return out;
}

ostream& operator<<(ostream &out, const bus_stop_corner &bsc) {
    out << "Bus stop at the corner of " << bsc.street1 << " and " << bsc.street2;
    return out;
}

void derivedClassTest() {
    derivedClassSave();
    derivedClassLoad();
}

void derivedClassSave() {
    gps_position lat;
    gps_position lng;

    lat.degrees = 1;
    lat.minutes = 2;
    lat.seconds = 3.3;

    lng.degrees = 4;
    lng.minutes = 5;
    lng.seconds = 6.66;

    bus_stop_corner bsc(lat, lng, "Str. A", "ul. B");

    cout << "Bus stop: " << bsc << endl;

    GenericSerializer<bus_stop_corner> serializer(bsc);
    serializer.save("bus_stop.dat");
}

void derivedClassLoad() {
    GenericSerializer<bus_stop_corner> serializer("bus_stop.dat");
    bus_stop_corner bsc = serializer.getData();

    cout << "Loaded bus stop: " << bsc << endl;
}

GenericSerializer.h

#ifndef BoostSerialization_GenericSerializer_h
#define BoostSerialization_GenericSerializer_h

#include <string>
using namespace std;

template <class Serializable>
class GenericSerializer {
private:
    Serializable *data;

public:
    GenericSerializer(const Serializable &s);
    ~GenericSerializer();
    void save(string filename);

    GenericSerializer(string filename);
    Serializable getData() const;
    void load(string filename);
};

#include "GenericSerializer.cpp"

#endif

GenericSerializer.cpp

//#define BINARY

#include <iostream>
#include <fstream>
#ifdef BINARY
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#else
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#endif
#include <string>
#include "GenericSerializer.h"
using namespace std;

template <class Serializable>
GenericSerializer<Serializable>::GenericSerializer(const Serializable &s) {
    this->data = new Serializable(s);
}

template <class Serializable>
GenericSerializer<Serializable>::~GenericSerializer() {
    delete this->data;
}

template <class Serializable>
void GenericSerializer<Serializable>::save(string filename) {
    ofstream ofs(filename.c_str(), ios::binary);
#ifdef BINARY
    boost::archive::binary_oarchive oa(ofs, boost::archive::no_header);
#else
    boost::archive::text_oarchive oa(ofs);
#endif
    oa << *data;
    ofs.close();
}

template <class Serializable>
GenericSerializer<Serializable>::GenericSerializer(string filename) {
    this->load(filename);
}

template <class Serializable>
Serializable GenericSerializer<Serializable>::getData() const {
    return *this->data;
}

template <class Serializable>
void GenericSerializer<Serializable>::load(string filename) {
    ifstream ifs(filename.c_str(), ios::binary);
#ifdef BINARY
    boost::archive::binary_iarchive ia(ifs, boost::archive::no_header);
#else
    boost::archive::text_iarchive ia(ifs);
#endif
    ia >> *data; 
}

Выход с GDB

Bus stop: Bus stop at the corner of Str. A and ul. B

Program received signal SIGSEGV, Segmentation fault. 0x00007ffff78fcf04 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::resize(unsigned long, char) () from /usr/lib/libstdc++.so.6
(gdb) bt
#0  0x00007ffff78fcf04 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::resize(unsigned long, char) () from /usr/lib/libstdc++.so.6
#1  0x00007ffff7ba395f in resize (this=0x7fffffffdc60, s=...) at /usr/include/c++/4.4/bits/basic_string.h:667
#2  boost::archive::basic_binary_iprimitive<boost::archive::binary_iarchive, char, std::char_traits<char> >::load (this=0x7fffffffdc60, s=...)
    at ./boost/archive/impl/basic_binary_iprimitive.ipp:111
#3  0x000000000040b9d8 in boost::archive::load_access::load_primitive<boost::archive::binary_iarchive, std::basic_string<char, std::char_traits<char>, std::allocator<char> >
> (ar=..., t=...) at /usr/include/boost/archive/detail/iserializer.hpp:107
#4  0x000000000040b73f in boost::archive::detail::load_non_pointer_type<boost::archive::binary_iarchive>::load_primitive::invoke<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (ar=..., t=...) at /usr/include/boost/archive/detail/iserializer.hpp:356
#5  0x000000000040b4f1 in boost::archive::detail::load_non_pointer_type<boost::archive::binary_iarchive>::invoke<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (ar=..., t=...) at /usr/include/boost/archive/detail/iserializer.hpp:433
#6  0x000000000040b07a in boost::archive::load<boost::archive::binary_iarchive, std::basic_string<char, std::char_traits<char>, std::allocator<char> >
> (
    ar=..., t=...) at /usr/include/boost/archive/detail/iserializer.hpp:580
#7  0x000000000040ad68 in boost::archive::detail::common_iarchive<boost::archive::binary_iarchive>::load_override<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (this=0x7fffffffdc50, t=...) at /usr/include/boost/archive/detail/common_iarchive.hpp:68
#8  0x000000000040ab6f in boost::archive::basic_binary_iarchive<boost::archive::binary_iarchive>::load_override<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (this=0x7fffffffdc50, t=..., version=0) at /usr/include/boost/archive/basic_binary_iarchive.hpp:67
#9  0x000000000040a921 in boost::archive::binary_iarchive_impl<boost::archive::binary_iarchive, char, std::char_traits<char> >::load_override<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (this=0x7fffffffdc50, t=...) at /usr/include/boost/archive/binary_iarchive_impl.hpp:50
#10 0x000000000040a6c8 in boost::archive::detail::interface_iarchive<boost::archive::binary_iarchive>::operator>><std::basic_string<char, std::char_traits<char>, std::allocator<char> > > (this=0x7fffffffdc50, t=...) at /usr/include/boost/archive/detail/interface_iarchive.hpp:61
#11 0x000000000040a445 in boost::archive::detail::interface_iarchive<boost::archive::binary_iarchive>::operator&<std::string> (this=0x7fffffffdc50, t=...)
    at /usr/include/boost/archive/detail/interface_iarchive.hpp:68
#12 0x000000000040a107 in bus_stop_corner::serialize<boost::archive::binary_iarchive> (this=0x62d958, ar=..., version=0) at Derived.h:62
#13 0x0000000000409c5c in boost::serialization::access::serialize<boost::archive::binary_iarchive, bus_stop_corner> (ar=..., t=..., file_version=0)
    at /usr/include/boost/serialization/access.hpp:118
#14 0x000000000040994f in boost::serialization::serialize<boost::archive::binary_iarchive, bus_stop_corner> (ar=..., t=..., file_version=0)
    at /usr/include/boost/serialization/serialization.hpp:74
#15 0x0000000000409544 in boost::serialization::serialize_adl<boost::archive::binary_iarchive, bus_stop_corner> (ar=..., t=..., file_version=0)
    at /usr/include/boost/serialization/serialization.hpp:133
#16 0x0000000000408f12 in boost::archive::detail::iserializer<boost::archive::binary_iarchive, bus_stop_corner>::load_object_data (this=0x62aa30, ar=..., 
    x=0x62d958, file_version=0) at /usr/include/boost/archive/detail/iserializer.hpp:182
#17 0x00007ffff7b9b857 in load_object (this=0x7fffffffdc50, t=<value optimized out>, bis=...) at libs/serialization/src/basic_iarchive.cpp:399
#18 boost::archive::detail::basic_iarchive::load_object (this=0x7fffffffdc50, t=<value optimized out>, bis=...)
    at libs/serialization/src/basic_iarchive.cpp:547
#19 0x000000000040838a in boost::archive::detail::load_non_pointer_type<boost::archive::binary_iarchive>::load_standard::invoke<bus_stop_corner> (ar=..., 
    t=...) at /usr/include/boost/archive/detail/iserializer.hpp:381
#20 0x0000000000408344 in boost::archive::detail::load_non_pointer_type<boost::archive::binary_iarchive>::invoke<bus_stop_corner> (ar=..., t=...)
    at /usr/include/boost/archive/detail/iserializer.hpp:433
#21 0x00000000004082dc in boost::archive::load<boost::archive::binary_iarchive, bus_stop_corner> (ar=..., t=...)
---Type <return> to continue, or q <return> to quit---
    at /usr/include/boost/archive/detail/iserializer.hpp:580
#22 0x0000000000408288 in boost::archive::detail::common_iarchive<boost::archive::binary_iarchive>::load_override<bus_stop_corner> (this=0x7fffffffdc50, 
    t=...) at /usr/include/boost/archive/detail/common_iarchive.hpp:68
#23 0x0000000000408233 in boost::archive::basic_binary_iarchive<boost::archive::binary_iarchive>::load_override<bus_stop_corner> (this=0x7fffffffdc50, t=..., 
    version=0) at /usr/include/boost/archive/basic_binary_iarchive.hpp:67
#24 0x00000000004081d7 in boost::archive::binary_iarchive_impl<boost::archive::binary_iarchive, char, std::char_traits<char> >::load_override<bus_stop_corner>
    (this=0x7fffffffdc50, t=...) at /usr/include/boost/archive/binary_iarchive_impl.hpp:50
#25 0x0000000000408150 in boost::archive::detail::interface_iarchive<boost::archive::binary_iarchive>::operator>><bus_stop_corner> (this=0x7fffffffdc50, 
    t=...) at /usr/include/boost/archive/detail/interface_iarchive.hpp:61
#26 0x0000000000407ff0 in GenericSerializer<bus_stop_corner>::load (this=0x7fffffffdf40, filename=...) at GenericSerializer.cpp:64
#27 0x0000000000407cff in GenericSerializer<bus_stop_corner>::GenericSerializer (this=0x7fffffffdf40, filename=...) at GenericSerializer.cpp:48
#28 0x00000000004063f1 in derivedClassLoad () at Derived.cpp:53
#29 0x00000000004060f9 in derivedClassTest () at Derived.cpp:29
#30 0x000000000040fcf7 in main (argc=1, argv=0x7fffffffe2b8) at main.cpp:44

bus_stop.dat (выходной файл сериализации)

22 serialization::archive 7 0 0 0 0 0 0 1 2 3.3 4 5 6.6599998 6 Str. A 5 ul. B

gcc -v -H

В Mac OS X

Using built-in specs.
Target: i686-apple-darwin11
Configured with: /private/var/tmp/llvmgcc42/llvmgcc42-2335.15~25/src/configure --disable-checking --enable-werror --prefix=/Developer/usr/llvm-gcc-4.2 --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-prefix=llvm- --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin11 --enable-llvm=/private/var/tmp/llvmgcc42/llvmgcc42-2335.15~25/dst-llvmCore/Developer/usr/local --program-prefix=i686-apple-darwin11- --host=x86_64-apple-darwin11 --target=i686-apple-darwin11 --with-gxx-include-dir=/usr/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)

в Ubuntu

Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.4.4-14ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)

Ответы [ 2 ]

0 голосов
/ 22 мая 2012

Буст-демо http://www.boost.org/doc/libs/1_42_0/libs/serialization/example/demo.cpp сработало у меня. Можете ли вы проверить свой код с помощью valgrind, чтобы убедиться в отсутствии ошибок памяти перед точкой инкриминирования?

0 голосов
/ 24 августа 2011

Некоторое время назад я помню, что у моего босса тоже были проблемы с сериализацией буста на его Mac.Проблема заключалась в использовании стандартных iostreams.Когда мы изменили код для использования boost iostreams, он работал на его Mac.

Мы не удосужились углубиться в это, так что на данный момент я могу только предложить вам попробовать то же самое и посмотреть,это работает:

boost::iostreams::stream_buffer<boost::iostreams::file_sink> ofs( "filename" );

PS Я пока не могу добавлять комментарии к вопросам, и мы не можем добавлять пользователей PM на SO ... поэтому я написал это как ответ.

Редактировать: OkЯ вижу, вы также тестировали на Ubuntu .. Я должен прочитать более внимательно.Тем не менее, возможно, стоит попробовать это, если это не сработает, я удалю этот ответ.

...