为什么非侵入式序列化要添加 5 字节零前缀?

2023-12-04

我正在研究使用 boost::archive 的应用程序中从非标准字符串到标准字符串的端口。非标准字符串的(反)序列化以非侵入式方式定义,如下例所示。序列化和反序列化按预期工作,但是当移植的应用程序收到旧消息时,它会因分配错误而崩溃。这是由于在字符串大小之前插入了 5 个字节(全为零)造成的。

是什么原因导致插入这5个额外字节呢?这是某种魔法标记吗?

Example:

#include <iostream>
#include <string>
#include <sstream>
#include <boost/serialization/split_free.hpp>
#include <boost/archive/binary_oarchive.hpp>

struct own_string { // simplified custom string class
    std::string content;
};

namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save(
            Archive & ar,
            const own_string & t,
            const unsigned int /* file_version */)
        {
            size_t size = t.content.size();
            ar << size;
            ar.save_binary(&t.content[0], size);
        }

        template<class Archive>
        inline void load(
            Archive & ar,
            own_string & t,
            const unsigned int /* file_version */)
        {
            size_t size;
            ar >> size;
            t.content.resize(size);
            ar.load_binary(&t.content[0], size);
        }

// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
        template<class Archive>
        inline void serialize(
            Archive & ar,
            own_string & t,
            const unsigned int file_version)
        {
            boost::serialization::split_free(ar, t, file_version);
        }

    } // namespace serialization
} // namespace boost

std::string string_to_hex(const std::string& input)
{
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();

    std::string output;
    output.reserve(2 * len);
    for (size_t i = 0; i < len; ++i)
    {
        const unsigned char c = input[i];
        output.push_back(lut[c >> 4]);
        output.push_back(lut[c & 15]);
    }
    return output;
}

void test_normal_string()
{
    std::stringstream ss;
    boost::archive::binary_oarchive ar{ss};

    std::string test = "";

    std::cout << string_to_hex(ss.str()) << std::endl;
    ar << test;

    //adds 00 00 00 00 00 00 00 00
    std::cout << string_to_hex(ss.str()) << std::endl;
}

void test_own_string()
{
    std::stringstream ss;
    boost::archive::binary_oarchive ar{ss};

    std::string test = "";

    own_string otest{test};
    std::cout << string_to_hex(ss.str()) << std::endl;
    ar << otest;

    //adds 00 00 00 00 00 00 00 00 00 00 00 00 00
    std::cout << string_to_hex(ss.str()) << std::endl;
}

int main()
{
    test_normal_string();
    test_own_string();
}

因此,您想要反序列化先前序列化的own_string就好像它是一个std::string.

From 提升(1.65.1)文档:

默认情况下,对于每个序列化的类,类信息都会写入存档中。此信息包括版本号、实现级别和跟踪行为。这是必要的,以便即使程序的后续版本更改了类的某些当前特征值,也可以正确反序列化存档。该数据的空间开销是最小的。由于必须检查每个类以查看其类信息是否已包含在存档中,因此存在一点运行时开销。在某些情况下,即使这样也可能被认为太过分了。通过将实现级别类特征设置为:boost::serialization::object_serialized,可以消除这种额外的开销。

现在,可能(*)这是标准类的默认设置。事实上,添加

BOOST_CLASS_IMPLEMENTATION(own_string, boost::serialization::object_serializable)

在全局范围内使 test_X_string 结果相同的字节。这应该可以解释观察到的额外字节差异。

也就是说,我未能找到有关标准类序列化特征的任何具体保证(其他人可能比我更了解)。

(*) 实际上是关于特征设置的可移植性部分提到:

避免此问题的另一种方法是将序列化特征分配给所有原始类型的模板 my_wrapper 的所有特化,以便永远不会保存类信息。这就是我们为 STL 集合实现序列化所做的事情

因此,这可能会给您足够的信心,标准集合(因此包括 std::string)在这种情况下会给出相同的字节。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么非侵入式序列化要添加 5 字节零前缀? 的相关文章

  • 如何在 Visual Studio 2010 中增强 XAML 设计器?

    当我使用 XAML 设计器时 进入设计器和退出设计器是如此困难和缓慢 当我这样做时 Visual Studio 卡了一段时间 有什么方法可以增强 XAML 设计器和编辑器吗 Ant 保存 XAML 文件时非常慢 这通常意味着您可能有复杂的
  • 如何在 C++ 中的文件末尾添加数据?

    我已按照网上的说明进行操作 此代码应该将输入添加到文件 数据库 的末尾 但当我检查时 数据会覆盖现有数据 请帮忙 这是我的代码 int main string name string address string handphone cou
  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • 如何读取扩展文件属性/文件元数据

    因此 我按照教程使用 ASP net core 将文件 上传 到本地路径 这是代码 public IActionResult About IList
  • 使用Physics.Raycast 和Physics2D.Raycast 检测对象上的点击

    我的场景中有一个空的游戏对象 带有 2D 组件盒碰撞器 我将脚本附加到该游戏对象 void OnMouseDown Debug Log clic 但是当我点击我的游戏对象时 没有任何效果 你有什么想法 如何检测我的盒子碰撞器上的点击 使用光
  • 如何检查QProcess是否正确执行?

    QProcess process sdcompare QString command sdcompare QStringList args sdcompare command sdcompare diff args sdcompare lt
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 将内置类型转换为向量

    我的 TcpClient 类接受vector
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • 在 C# 中循环遍历文件文件夹的最简单方法是什么?

    我尝试编写一个程序 使用包含相关文件路径的配置文件来导航本地文件系统 我的问题是 在 C 中执行文件 I O 这将是从桌面应用程序到服务器并返回 和文件系统导航时使用的最佳实践是什么 我知道如何谷歌 并且找到了几种解决方案 但我想知道各种功
  • 关于在 Windows 上使用 WiFi Direct Api?

    我目前正在开发一个应用程序 我需要在其中创建链接 阅读 无线网络连接 在桌面应用程序 在 Windows 10 上 和平板电脑 Android 但无关紧要 之间 工作流程 按钮 gt 如果需要提升权限 gt 创建类似托管网络的 WiFi 网
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • Process.Start() 方法在什么情况下返回 false?

    From MSDN https msdn microsoft com en us library e8zac0ca v vs 110 aspx 返回值 true 表示有新的进程资源 开始了 如果由 FileName 成员指定的进程资源 St
  • 如何将 Roslyn 语义模型返回的类型符号名称与 Mono.Cecil 返回的类型符号名称相匹配?

    我有以下代码 var paramDeclType m semanticModel GetTypeInfo paramDecl Type Type Where paramDeclType ToString returns System Col
  • 使用 GhostScript.NET 打印 PDF DPI 打印问题

    我在用GhostScript NET http ghostscriptnet codeplex com打印 PDF 当我以 96DPI 打印时 PDF 打印效果很好 但有点模糊 如果我尝试以 600DPI 打印文档 打印的页面会被极大地放大
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当

随机推荐