使用boost序列化抽象类时出错(Error serializing an abstract class with boost)

编程入门 行业动态 更新时间:2024-10-28 13:18:18
使用boost序列化抽象类时出错(Error serializing an abstract class with boost)

我正在尝试序列化我的数据结构,以便将它们写入tcp套接字。

到目前为止,我发现我的问题是序列化。 我甚至试过用

BOOST_SERIALIZATION_ASSUME_ABSTRACT(T)
 

但我找不到任何与我的程序类似的工作示例以及如何正确实现它。

以下是我访问过的一些链接:

http://programmers-blog.com/category/cc http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/tutorial.html#simplecase http://en.highscore.de/cpp/boost/serialization.html#serialization_class_hierarchies

我的数据结构比这个更复杂,但我们假设我有以下结构

Coordinate.h

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

class Coordinate {
public:
    Coordinate() {}
    Coordinate(int c) : c(c) {}
    int get(void) { return c; }
    std::string toString(void);
private:
    int c;
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & this->c;
    }
};
 

Move.h

class Coordinate;

#include "Coordinate.h"

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

class Move {
public:
    Move() {}
    ~Move() {}
    Coordinate* getCoordinate(void) {return this->destination; }
    virtual bool isJump(void) = 0;
protected:
    Coordinate *destination;
private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & this->destination;
    }
};
 

MoveNormal.h

class Coordinate;

#include "Move.h"
#include "Coordinate.h"

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

class MoveNormal : public Move {
public:
    MoveNormal() {}
    MoveNormal(Coordinate *destination) { this->destination = destination; }
    ~MoveNormal() {}
    virtual bool isJump(void);
private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & boost::serialization::base_object<Move>(*this);
    }
};
 

虚拟方法在此处定义。

MoveNormal.cpp

#include "MoveNormal.h"

bool MoveNormal::isJump(void) {
    return false;
}
 

我的main.cpp看起来像这样:

#include "Coordinate.h"
#include "Move.h"
#include "MoveNormal.h"

#include <fstream>

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

int main(int argc, char *argv[]) {
    Coordinate *c = new Coordinate(10);
    // This runs OK
    /*
    {
        std::ofstream ofs("f.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << c;
    }
    Coordinate *d;
    {
        std::ifstream ifs("f.txt");
        boost::archive::text_iarchive ia(ifs);
        ia >> d;
    }
    std::cout << "c.get(): " << c->get() << std::endl;
    std::cout << "d.get(): " << d->get() << std::endl;
    */

    // This is where I get my error
    Move *m  = new MoveNormal(c);
    {
        std::ofstream ofs("f.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << m;    // Line where the error occurs
    }
    return 0;
}
 

但是当我运行程序时,我收到以下错误:

Test.exe中0x76dbb9bc处的未处理异常:Microsoft C ++异常:内存位置0x001df078处的boost :: archive :: archive_exception ..

我正在使用VS2010和Boost 1.48.0。

I'm trying to serialize my data structures in order to write them to a tcp socket.

So far I found that my problem is the serialization. I even tried to use

BOOST_SERIALIZATION_ASSUME_ABSTRACT(T)
 

but I can't find any working example similar to my program and how to implement it correctly.

Here are some of the links that I have visited:

http://programmers-blog.com/category/c-c http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/tutorial.html#simplecase http://en.highscore.de/cpp/boost/serialization.html#serialization_class_hierarchies

My data structures are a little more complicated then this one but let's assume that I have the following structure

Coordinate.h

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

class Coordinate {
public:
    Coordinate() {}
    Coordinate(int c) : c(c) {}
    int get(void) { return c; }
    std::string toString(void);
private:
    int c;
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & this->c;
    }
};
 

Move.h

class Coordinate;

#include "Coordinate.h"

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

class Move {
public:
    Move() {}
    ~Move() {}
    Coordinate* getCoordinate(void) {return this->destination; }
    virtual bool isJump(void) = 0;
protected:
    Coordinate *destination;
private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & this->destination;
    }
};
 

MoveNormal.h

class Coordinate;

#include "Move.h"
#include "Coordinate.h"

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

class MoveNormal : public Move {
public:
    MoveNormal() {}
    MoveNormal(Coordinate *destination) { this->destination = destination; }
    ~MoveNormal() {}
    virtual bool isJump(void);
private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & boost::serialization::base_object<Move>(*this);
    }
};
 

The virtual methods are defined in here.

MoveNormal.cpp

#include "MoveNormal.h"

bool MoveNormal::isJump(void) {
    return false;
}
 

My main.cpp looks like this:

#include "Coordinate.h"
#include "Move.h"
#include "MoveNormal.h"

#include <fstream>

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

int main(int argc, char *argv[]) {
    Coordinate *c = new Coordinate(10);
    // This runs OK
    /*
    {
        std::ofstream ofs("f.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << c;
    }
    Coordinate *d;
    {
        std::ifstream ifs("f.txt");
        boost::archive::text_iarchive ia(ifs);
        ia >> d;
    }
    std::cout << "c.get(): " << c->get() << std::endl;
    std::cout << "d.get(): " << d->get() << std::endl;
    */

    // This is where I get my error
    Move *m  = new MoveNormal(c);
    {
        std::ofstream ofs("f.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << m;    // Line where the error occurs
    }
    return 0;
}
 

But when I run the program I get the following error:

Unhandled exception at 0x76dbb9bc in Test.exe: Microsoft C++ exception: boost::archive::archive_exception at memory location 0x001df078..

I'm using VS2010, and Boost 1.48.0.

最满意答案

这有点奇怪,但我会回答我自己的问题。 我只是弄清楚如何使我的例子在上面工作。

这是解决方案。 每次我们需要序列化从另一个类继承属性的类时,我们需要使用宏:

BOOST_CLASS_EXPORT(T)

根据boost序列化文档

包含任何归档类头的同一源模块中的BOOST_CLASS_EXPORT将实例化将所指示类型的多态指针序列化到所有这些归档类所需的代码。 如果未包含归档类头,则不会实例化任何代码。

请注意,此功能的实现要求BOOST_CLASS_EXPORT宏出现在后面并包含要为其实例化代码的任何归档类头。

所以在我的情况下我的main.cpp文件现在是:

#include <fstream>

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>

#include "Coordinate.h"
#include "Move.h"
#include "MoveNormal.h"
BOOST_CLASS_EXPORT(MoveNormal)

int main(int argc, char *argv[]) {
    Coordinate *c = new Coordinate(150);
    Move *m = new MoveNormal(c);
    std::cout << "m.getDestination().get(): " << m->getDestination()->get() << std::endl;
    {
        std::ofstream ofs("f.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << m;
    }

    Move *n;
    {
        std::ifstream ifs("f.txt");
        boost::archive::text_iarchive ia(ifs);
        ia >> n;
    }
    std::cout << "n.getDestination().get(): " << n->getDestination()->get() << std::endl;
    return 0;
}
 

在使用导出MACRO之前,请确保包含所需的所有增强存档。

要完成除序列化之外的项目,我需要使用boost :: asio将它们写入tcp套接字。

所以我们假设我有一个像这样的连接头,现在我在MoveJump.h中定义了一个名为MoveJump的类。

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

#include "Coordinate.h"
#include "Move.h"

class MoveJump : public Move {
public:
    MoveJump() {}
    MoveJump(Coordinate *c) { this->destinatio = c; }
    ~MoveJump() {}
    virtual bool isJump(void);
private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serializize(Archive &ar, const unsigned int version) {
        ar & boost::serialization::base_object<Move>(*this);
    }
};
 

现在序列化这些结构我的主要看起来像这样

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>

#include <fstream>

#include "Coordinate.h"
#include "Move.h"
// And now we register all the possible Moves
#include "MoveNormal.h"
BOOST_CLASS_EXPORT(MoveNormal)
#include "MoveJump.h"
BOOST_CLASS_EXPORT(MoveJump)

int main(int argc, char *argv[]) {
    Coordinate *c = new Coordinate(10);
    Move *m = new MoveNormal(c);
    Coordinate *d = new Coordinate(15);
    Move *j = new MoveJump(d);
    {
        std::ofstream ofs("m.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << m;
    }
    {
        std::ofstream ofs("j.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << j;
    }
}
 

诀窍是在我们有指向基类的指针时注册将被序列化的类。

如果在我的Move.h中我有更多指向其他基类的指针,我在项目中做了,我们需要在main中包含所有头文件并注册扩展基类的所有可能的类。

我希望这有助于将来可能遇到类似问题的人。

随意提出新的可能解决方案。

谢谢

This is a little bit weird but I'm going to answer my own question. I just figured out how to make my example above work.

Here it goes the solution. Everytime we need to serialize a class that inherits attributes from another class we need to use the macro:

BOOST_CLASS_EXPORT(T)

According to the boost serialization doc

BOOST_CLASS_EXPORT in the same source module that includes any of the archive class headers will instantiate code required to serialize polymorphic pointers of the indicated type to the all those archive classes. If no archive class headers are included, then no code will be instantiated.

Note that the implemenation of this functionality requires that the BOOST_CLASS_EXPORT macro appear after and the inclusion of any archive class headers for which code is to be instantiated.

So in my case my main.cpp file is now:

#include <fstream>

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>

#include "Coordinate.h"
#include "Move.h"
#include "MoveNormal.h"
BOOST_CLASS_EXPORT(MoveNormal)

int main(int argc, char *argv[]) {
    Coordinate *c = new Coordinate(150);
    Move *m = new MoveNormal(c);
    std::cout << "m.getDestination().get(): " << m->getDestination()->get() << std::endl;
    {
        std::ofstream ofs("f.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << m;
    }

    Move *n;
    {
        std::ifstream ifs("f.txt");
        boost::archive::text_iarchive ia(ifs);
        ia >> n;
    }
    std::cout << "n.getDestination().get(): " << n->getDestination()->get() << std::endl;
    return 0;
}
 

Just make sure that you include all the boost archives you need before you use the export MACRO.

To finish my project besides the serialization I need to write them to a tcp socket using boost::asio.

So let's assume that I have a connection header like this one and that now I have another class called MoveJump defined in my MoveJump.h

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>

#include "Coordinate.h"
#include "Move.h"

class MoveJump : public Move {
public:
    MoveJump() {}
    MoveJump(Coordinate *c) { this->destinatio = c; }
    ~MoveJump() {}
    virtual bool isJump(void);
private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serializize(Archive &ar, const unsigned int version) {
        ar & boost::serialization::base_object<Move>(*this);
    }
};
 

Now to serialize these structures my main look like this

#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>

#include <fstream>

#include "Coordinate.h"
#include "Move.h"
// And now we register all the possible Moves
#include "MoveNormal.h"
BOOST_CLASS_EXPORT(MoveNormal)
#include "MoveJump.h"
BOOST_CLASS_EXPORT(MoveJump)

int main(int argc, char *argv[]) {
    Coordinate *c = new Coordinate(10);
    Move *m = new MoveNormal(c);
    Coordinate *d = new Coordinate(15);
    Move *j = new MoveJump(d);
    {
        std::ofstream ofs("m.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << m;
    }
    {
        std::ofstream ofs("j.txt");
        boost::archive::text_oarchive oa(ofs);
        oa << j;
    }
}
 

The trick is to register the classes that will be serialized when we have the pointer to the base class.

If inside my Move.h I have more pointers to other base classes, which I do in my project, we need to include in the main all the headers and register all the possible classes that expand the base class.

I hope this helps someone who might have similar problems in the future.

Feel free to present new possible solutions.

Thanks

更多推荐

本文发布于:2023-08-07 21:50:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1466052.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:序列化   抽象类   boost   Error   class

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!