微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

自定义 boost 序列化输入存档仅在使用向量时失败 (boost::archive::archive_exception)

如何解决自定义 boost 序列化输入存档仅在使用向量时失败 (boost::archive::archive_exception)

我正在使用 boost 序列化,并且我编写了一个源自 boost 二进制输入存档的自定义输入存档。事件虽然这个类现在与 boost 的 binary_iarchive 完全一样,但在反序列化原始类型的 boost::archive::archive_exception 时我得到一个 std::vector。我没有遇到任何序列化问题,例如std::stringstd::vector<std::string>

完整代码如下:

InputArchive 实现:

#ifndef __INPUT_ARCHIVE_H
#define __INPUT_ARCHIVE_H

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>

class InputArchive;

using iarchive = boost::archive::binary_iarchive_impl<
    InputArchive,std::istream::char_type,std::istream::traits_type>;

class InputArchive : public iarchive {

    friend class boost::archive::detail::interface_iarchive<InputArchive>;
    friend class boost::archive::basic_binary_iarchive<InputArchive>;
    friend class boost::archive::load_access;

    public:

    template<typename ... Args>
    InputArchive(Args&& ... args)
    : iarchive(std::forward<Args>(args)...,boost::archive::archive_flags::no_header)
    {}

};

#endif

虚拟类,用于测试目的:

#ifndef __DUMMY_PRODUCT_H
#define __DUMMY_PRODUCT_H

#include <vector>
#include <boost/serialization/vector.hpp>
#include <string>
#include <boost/serialization/string.hpp>

struct dummy_product {
    std::vector<char> data;

    template<typename A>
    void serialize(A& ar,const unsigned int version) {
        ar & data;
    }

};

#endif

以及使用存档的示例代码

#include <boost/archive/binary_oarchive.hpp>
#include "InputArchive.hpp"
#include "DummyProduct.hpp"
#include <string>
#include <sstream>
#include <iostream>

int main() {

    dummy_product p;
    p.data.resize(16);

    std::string buffer;
    {
        std::stringstream ss_value;
        boost::archive::binary_oarchive oa(ss_value,boost::archive::archive_flags::no_header);
        oa << p;
        buffer = ss_value.str();
    }
    for(auto i : buffer) {
        std::cout << (int)i << " ";
    }
    std::cout << std::endl;

    {
        std::stringstream ss_value(buffer);
        //boost::archive::binary_iarchive ia(ss_value,boost::archive::archive_flags::no_header);
        InputArchive ia(ss_value);
        ia >> p;
    }

}

代码抛出以下异常:

terminate called after throwing an instance of 'boost::archive::archive_exception'
  what():  input stream error

如您所见,InputArchive 只是从相应的 boost::archive::binary_iarchive_impl 继承而没有执行任何其他操作。如果我用 boost::archive::binary_iarchive 替换 InputArchive,则没有问题。如果我在 std::string 中使用 std::vector<char> 而不是 dummy_product 也没有问题。异常似乎只发生在原始类型的 std::vector 上。

知道这个问题是从哪里来的吗? 我使用的是 boost 1.75.0 和 gcc 8.3.0。

解决方法

缺少两个主要的东西:

  1. 问题。如您所见,InputArchive 只是从适当的 boost::archive::binary_iarchive_impl 继承而没有其他任何操作。

    A. 是的,但不是以适当的方式。您的构造函数忘记初始化存档。只需转发到基类构造函数就完成了一半的工作:

    enum {
        forced_flags = boost::archive::archive_flags::no_header
    };
    
    InputArchive(std::istream & is,unsigned int flags = 0) :
        iarchive(is,flags | forced_flags)
    {
        init(flags | forced_flags);
    }
    InputArchive(std::streambuf & bsb,unsigned int flags = 0) :
        iarchive(bsb,flags | forced_flags)
    {
        init(flags | forced_flags);
    }
    
  2. 接下来,对允许按位二进制输出的存档的原始类型进行了优化。你的就是其中之一,所以你需要告诉 Boost:

    BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(InputArchive)
    
  3. 为了真的很酷,您可能还想正确地获得注册到存档类型的多态类型的类型信息。如果你这样做了,你也想告诉 Boost :

    BOOST_SERIALIZATION_REGISTER_ARCHIVE(InputArchive)
    

松散的笔记:

  • 我不确定 friends 的用途。这可能是我的性格缺陷
  • 考虑将事物移动到命名空间中,例如::iarchive 不会无缘无故地污染全局命名空间。 [另外,考虑使用 CRTP 并在类定义中拼出名称。]

现在可以使用了

Live On Wandbox

#ifndef __INPUT_ARCHIVE_H
#define __INPUT_ARCHIVE_H

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>

class InputArchive;

using iarchive = boost::archive::binary_iarchive_impl<
    InputArchive,std::istream::char_type,std::istream::traits_type>;

class InputArchive : public iarchive {
    enum {
        forced_flags = boost::archive::archive_flags::no_header
    };

    //friend class boost::archive::detail::interface_iarchive<InputArchive>;
    //friend class boost::archive::basic_binary_iarchive<InputArchive>;
    //friend class boost::archive::load_access;
  public:
    InputArchive(std::istream & is,unsigned int flags = 0) :
        iarchive(is,flags | forced_flags)
    {
        init(flags | forced_flags);
    }
    InputArchive(std::streambuf & bsb,unsigned int flags = 0) :
        iarchive(bsb,flags | forced_flags)
    {
        init(flags | forced_flags);
    }
};

// required by export
BOOST_SERIALIZATION_REGISTER_ARCHIVE(InputArchive)
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(InputArchive)

#endif

#ifndef __DUMMY_PRODUCT_H
#define __DUMMY_PRODUCT_H

#include <vector>
#include <boost/serialization/vector.hpp>
#include <string>
#include <boost/serialization/string.hpp>

struct dummy_product {
    std::vector<char> data;

    template<typename A>
    void serialize(A& ar,unsigned) {
        ar & data;
    }

};

#endif

#include <boost/archive/binary_oarchive.hpp>
//#include "InputArchive.hpp"
//#include "DummyProduct.hpp"
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>

int main() {

    dummy_product p;
    p.data.resize(16);

    std::string buffer;
    {
        std::stringstream ss_value;
        boost::archive::binary_oarchive oa(ss_value,boost::archive::archive_flags::no_header);
        oa << p;
        buffer = ss_value.str();
    }
    for(int i : buffer) {
        std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)i << " ";
    }
    std::cout << std::endl;

    {
        std::stringstream ss_value(buffer);
        // boost::archive::binary_iarchive ia(ss_value,boost::archive::archive_flags::no_header);
        InputArchive ia(ss_value);
        ia >> p;
    }

}

印刷品

00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?