【问题标题】:How does Boost::serialization store user-defined classes in archives?Boost::serialization 如何在档案中存储用户定义的类?
【发布时间】:2026-02-22 14:35:01
【问题描述】:

我有一个用户定义的对象(称为Foo),它由一些原始变量以及已经包含serialize 函数实现的其他(外部库)对象组成。 我想知道存档文件的结构,以及该结构是否通用(例如在文本存档和二进制存档之间)。 当我在文本编辑器中打开文本存档时,第一个字符是 22 serialization::archive 19 0 0。 以下似乎是来自我的用户定义对象的所有数据。

我的问题是:这些初始字符对应什么?如果我尝试将文件的内容输出到不是Foo 的内容中,如下所示:

bool bool1;
bool bool2;

ia >> bool1 >> bool2;

它似乎只输出前几个零——它对任何存档都这样做吗? 如果是这样,只需读入适当的类型,就可以从该存档中读出Foo 的所有成员变量,如下所示:

bool bool1;
bool bool2;
double Foo_member1;
std::string Foo_member2;

ia >> bool1 >> bool2 >> Foo_member1 >> Foo_member2;

最后,这种结构是否也适用于任何其他类型的存档(例如二进制存档)?

【问题讨论】:

  • 旁注:您可以通过使用诸如no_headerno_codecvt 甚至no_tracking 之类的归档标志来减少开销。我强烈建议不要,除非你绝对知道你在做什么。稍有更改(例如 boost 库更新),您就有可能丢失数据。

标签: c++ boost boost-serialization


【解决方案1】:

它似乎只输出前几个零

什么意思?您使用 不确定值 序列化了两个变量(您从未初始化它们)。你不应该期待零。您也不应该期待任何特定的布局(它由存档类型、版本、库版本和平台架构决定)。

想知道存档文件的结构,以及该结构是否通用

这取决于存档。它“通用的”(对于通用的一些定义)。但是,大多数存档格式包含描述其结构的最少元数据(它们不能以非顺序方式“访问”或“遍历”,也没有某种“可反射”模式)。如果您需要这些类型的序列化功能,请查看其他(protobuf、msgpack、bson、XML/XSD 等)。

最能满足您好奇心的一种存档类型是 XML 存档类型。你会发现你需要为 XML 元素提供语义信息,例如

Live On Coliru

#include <boost/archive/xml_oarchive.hpp>
#include <iostream>

int main() {
    using boost::serialization::make_nvp;
    {
        boost::archive::xml_oarchive oa(std::cout);

        int a = 42, b = 99, c = a * b;
        oa << make_nvp("a", a) << make_nvp("b", b) << make_nvp("c", c);
    } // closes the archive
}

结果

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="19">
  <a>42</a>
  <b>99</b>
  <c>4158</c>
</boost_serialization>

这至少会为版本 (19) 和类似信息提供一些可识别的上下文。例如。与对象跟踪和标识、RTTI 映射和导出的类键等有关。

如果是这样,通过读入适当的类型来从该存档中读出 Foo 的所有成员变量是否合理

是的,但也许不是。您必须履行的合同是以完全相同的顺序(反)序列化完全相同类型的数据。你管理的任何方式都很好。典型的方法是为您的类型实现serialize,而不是单独序列化成员(Law Of Demeter 和简单的Encapsulation):

Live On Coliru

#include <boost/archive/xml_oarchive.hpp>

namespace MyLib {
    struct Foo {
        bool        bool1;
        bool        bool2;
        double      Foo_member1;
        std::string Foo_member2;
    };

    template <typename Ar>
    void serialize(Ar& ar, Foo& foo, unsigned /*version*/)
    {
        ar& BOOST_NVP(foo.bool1) & BOOST_NVP(foo.bool2) &
            BOOST_NVP(foo.Foo_member1) & BOOST_NVP(foo.Foo_member2);
    }
} // namespace MyLib

#include <cmath> // for M_PI...
#include <iostream>
int main() {
    using boost::serialization::make_nvp;
    {
        boost::archive::xml_oarchive oa(std::cout);

        MyLib::Foo foo{true, false, M_PI, "Hello world"};
        oa << make_nvp("foo", foo);
    } // closes the archive
}

打印

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="19">
<foo class_id="0" tracking_level="0" version="0">
    <foo.bool1>1</foo.bool1>
    <foo.bool2>0</foo.bool2>
    <foo.Foo_member1>3.14159265358979312e+00</foo.Foo_member1>
    <foo.Foo_member2>Hello world</foo.Foo_member2>
</foo>
</boost_serialization>

警告

听起来确实有点像您将存档误认为具有某种标准格式的随机访问数据流。查看更多Archives are not streams

【讨论】:

最近更新 更多