自定义 boost 序列化输入存档仅对向量失败 (boost::archive::archive_exception)
Custom boost serialization input archive fails only with vectors (boost::archive::archive_exception)
我正在使用 boost 序列化,我已经编写了一个自定义输入存档,它派生自 boost 的二进制输入存档。尽管此 class 目前与 boost 的 binary_iarchive 完全相同,但在反序列化原始类型的 std::vector
时我得到了 boost::archive::archive_exception
。我没有遇到任何序列化问题,例如std::string
或 std::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
虚拟 class,用于测试目的:
#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
,仅此而已。如果我将 InputArchive 替换为 boost::archive::binary_iarchive
则没有问题。如果我在 dummy_product
中使用 std::string
而不是 std::vector<char>
也没有问题。异常似乎只发生在 std::vector
原始类型中。
知道这个问题是从哪里来的吗?
我正在使用 boost 1.75.0 和 gcc 8.3.0.
缺少两个主要的东西:
-
Q. As you can see, the InputArchive simply inherits from the appropriate boost::archive::binary_iarchive_impl and does nothing more.
A. 是的,但不是以适当的方式。您的构造函数忘记初始化存档。只需转发到基础 class 构造函数就完成了一半的工作:
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);
}
接下来,对允许按位二进制输出的存档的原始类型进行了优化。你的就是其中之一,所以你需要告诉Boost:
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(InputArchive)
为了真正酷,您可能还想正确地为您的存档类型注册多态类型的类型信息。如果你这样做了,你也想告诉 Boost:
BOOST_SERIALIZATION_REGISTER_ARCHIVE(InputArchive)
零散笔记:
- 我不确定
friends
的用途。这可能是我的性格缺陷
- 考虑将事物移动到命名空间中,例如
::iarchive
不会无缘无故地污染全局命名空间。 [此外,考虑只使用 CRTP 并在 class 定义中拼出名称。]
现在可以使用了
#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
我正在使用 boost 序列化,我已经编写了一个自定义输入存档,它派生自 boost 的二进制输入存档。尽管此 class 目前与 boost 的 binary_iarchive 完全相同,但在反序列化原始类型的 std::vector
时我得到了 boost::archive::archive_exception
。我没有遇到任何序列化问题,例如std::string
或 std::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
虚拟 class,用于测试目的:
#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
,仅此而已。如果我将 InputArchive 替换为 boost::archive::binary_iarchive
则没有问题。如果我在 dummy_product
中使用 std::string
而不是 std::vector<char>
也没有问题。异常似乎只发生在 std::vector
原始类型中。
知道这个问题是从哪里来的吗? 我正在使用 boost 1.75.0 和 gcc 8.3.0.
缺少两个主要的东西:
-
Q. As you can see, the InputArchive simply inherits from the appropriate boost::archive::binary_iarchive_impl and does nothing more.
A. 是的,但不是以适当的方式。您的构造函数忘记初始化存档。只需转发到基础 class 构造函数就完成了一半的工作:
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); }
接下来,对允许按位二进制输出的存档的原始类型进行了优化。你的就是其中之一,所以你需要告诉Boost:
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(InputArchive)
为了真正酷,您可能还想正确地为您的存档类型注册多态类型的类型信息。如果你这样做了,你也想告诉 Boost:
BOOST_SERIALIZATION_REGISTER_ARCHIVE(InputArchive)
零散笔记:
- 我不确定
friends
的用途。这可能是我的性格缺陷 - 考虑将事物移动到命名空间中,例如
::iarchive
不会无缘无故地污染全局命名空间。 [此外,考虑只使用 CRTP 并在 class 定义中拼出名称。]
现在可以使用了
#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