You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++含自定义类型成员的Mango类序列化反序列化最优实现问询

问题描述

需要实现C++类Mango的序列化与反序列化函数,该类包含10个类似MangoType的复杂自定义类型成员。当前已定义框架函数,但不确定:

  • serialize的返回类型(比如std::vector<uint8_t>还是直接写入内存)
  • deserialize的参数类型
    希望获得兼顾速度、内存占用、可移植性的最优实现方案。

场景说明

序列化后的数据仅用于本地存储复用,无需网络传输,目的是避免每次重新计算加载Mango数据的耗时。

额外需求

不想使用需要链接的序列化库,询问能否以仅头文件形式使用Boost Serialization。

相关代码框架

? serialize(Mango &Man) /// What should be return ?
{
}

Mango deserialize(  ?   ) /// What should be function parameter ?
{
}

类定义

Mango类

class Mango
{
public:
    const MangoType &getMangoType() const { return typeMan; }
    MangoType &getMangoType() { return typeMan; }

private:
    // 实际包含10个不同类型的成员,此处仅示例一个
    MangoType typeMan;
};

自定义数据类型

// MangoType类
class MangoType
{
public:
    std::vector<FuntionMango> &getContent() noexcept { return Content; }

private:
    std::vector<FuntionMango> Content;
};

// FuntionMango类
class FuntionMango
{
public:
    const std::vector<ValType> &getParamTypes() const noexcept
    {
        return ParamTypes;
    }
    std::vector<ValType> &getParamTypes() noexcept { return ParamTypes; }

    const std::vector<ValType> &getReturnTypes() const noexcept
    {
        return ReturnTypes;
    }
    std::vector<ValType> &getReturnTypes() noexcept { return ReturnTypes; }

private:
    std::vector<ValType> ParamTypes;
    std::vector<ValType> ReturnTypes;
};

// ValType枚举类
enum class ValType : uint8_t
{
    #define UseValType
    #define Line(NAME, VALUE, STRING) NAME = VALUE
    #undef Line
    #undef UseValType
};

解决方案

一、序列化/反序列化的类型选择

1. serialize返回类型:std::vector<uint8_t>

  • 速度:内存中连续存储,写入文件时可一次性IO,减少磁盘操作次数;
  • 内存占用:仅存储实际序列化数据,无额外冗余,可先在内存构建完整数据再落地,避免多次文件IO开销;
  • 可移植性:标准容器跨平台兼容,手动处理多字节类型的字节序即可保证不同系统间的兼容性。

2. deserialize参数类型:const std::vector<uint8_t>& 或 std::span<const uint8_t>(C++20+)

  • const std::vector<uint8_t>&:兼容性最好,支持所有C++版本;
  • std::span<const uint8_t>:更轻量,无需拷贝整个缓冲区,适合C++20及以上环境,内存占用更低。

二、Boost Serialization仅头文件使用方式

完全可以仅用头文件形式使用Boost Serialization:只需在项目中定义宏BOOST_SERIALIZATION_DYN_LINK=0(或直接不定义BOOST_SERIALIZATION_DYN_LINK),包含所需头文件即可,无需链接Boost序列化库。

三、具体实现示例

1. 手动序列化(无外部依赖)

适合轻量场景,速度和内存控制最优,但需手动处理所有类型:

#include <vector>
#include <cstdint>
#include <algorithm>

// 辅助:写入POD类型到缓冲区
template<typename T>
void write_pod(std::vector<uint8_t>& buf, const T& val)
{
    static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>, "T must be POD");
    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&val);
    buf.insert(buf.end(), ptr, ptr + sizeof(T));
}

// 辅助:从缓冲区读取POD类型
template<typename T>
T read_pod(const uint8_t*& ptr)
{
    static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>, "T must be POD");
    T val = *reinterpret_cast<const T*>(ptr);
    ptr += sizeof(T);
    return val;
}

std::vector<uint8_t> serialize(const Mango& man)
{
    std::vector<uint8_t> buf;

    // 序列化MangoType
    const auto& type_man = man.getMangoType();
    const auto& content = type_man.getContent();
    uint32_t content_size = static_cast<uint32_t>(content.size());
    write_pod(buf, content_size);

    for (const auto& func : content)
    {
        // 序列化ParamTypes
        uint32_t param_size = static_cast<uint32_t>(func.getParamTypes().size());
        write_pod(buf, param_size);
        for (ValType vt : func.getParamTypes())
        {
            write_pod(buf, static_cast<uint8_t>(vt));
        }

        // 序列化ReturnTypes
        uint32_t return_size = static_cast<uint32_t>(func.getReturnTypes().size());
        write_pod(buf, return_size);
        for (ValType vt : func.getReturnTypes())
        {
            write_pod(buf, static_cast<uint8_t>(vt));
        }
    }

    // 添加其他9个Mango成员的序列化逻辑...

    return buf;
}

Mango deserialize(const std::vector<uint8_t>& buf)
{
    Mango man;
    const uint8_t* ptr = buf.data();
    const uint8_t* end = ptr + buf.size();

    // 反序列化MangoType
    auto& type_man = man.getMangoType();
    auto& content = type_man.getContent();
    uint32_t content_size = read_pod<uint32_t>(ptr);
    content.reserve(content_size);

    for (uint32_t i = 0; i < content_size; ++i)
    {
        FuntionMango func;

        // 反序列化ParamTypes
        uint32_t param_size = read_pod<uint32_t>(ptr);
        auto& params = func.getParamTypes();
        params.reserve(param_size);
        for (uint32_t j = 0; j < param_size; ++j)
        {
            uint8_t vt_val = read_pod<uint8_t>(ptr);
            params.emplace_back(static_cast<ValType>(vt_val));
        }

        // 反序列化ReturnTypes
        uint32_t return_size = read_pod<uint32_t>(ptr);
        auto& returns = func.getReturnTypes();
        returns.reserve(return_size);
        for (uint32_t j = 0; j < return_size; ++j)
        {
            uint8_t vt_val = read_pod<uint8_t>(ptr);
            returns.emplace_back(static_cast<ValType>(vt_val));
        }

        content.push_back(std::move(func));
    }

    // 添加其他9个Mango成员的反序列化逻辑...

    return man;
}

2. Boost Serialization仅头文件实现

代码简洁,无需手动处理复杂容器,维护成本低:

#define BOOST_SERIALIZATION_DYN_LINK 0 // 禁用动态链接,仅用头文件
#include <boost/serialization/vector.hpp>
#include <boost/serialization/access.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <vector>
#include <sstream>

// 为MangoType添加序列化支持
class MangoType
{
public:
    std::vector<FuntionMango> &getContent() noexcept { return Content; }
    const std::vector<FuntionMango> &getContent() const noexcept { return Content; }

private:
    std::vector<FuntionMango> Content;

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar & Content;
    }
};

// 为FuntionMango添加序列化支持
class FuntionMango
{
public:
    const std::vector<ValType> &getParamTypes() const noexcept { return ParamTypes; }
    std::vector<ValType> &getParamTypes() noexcept { return ParamTypes; }

    const std::vector<ValType> &getReturnTypes() const noexcept { return ReturnTypes; }
    std::vector<ValType> &getReturnTypes() noexcept { return ReturnTypes; }

private:
    std::vector<ValType> ParamTypes;
    std::vector<ValType> ReturnTypes;

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar & ParamTypes & ReturnTypes;
    }
};

// 为Mango添加序列化支持
class Mango
{
public:
    const MangoType &getMangoType() const { return typeMan; }
    MangoType &getMangoType() { return typeMan; }

private:
    MangoType typeMan;
    // 其他9个成员...

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar & typeMan;
        // 序列化其他9个成员...
    }
};

// 序列化函数
std::vector<uint8_t> serialize(const Mango& man)
{
    std::ostringstream oss;
    boost::archive::binary_oarchive oa(oss);
    oa << man;

    const std::string& str = oss.str();
    return std::vector<uint8_t>(str.begin(), str.end());
}

// 反序列化函数
Mango deserialize(const std::vector<uint8_t>& buf)
{
    std::string str(buf.begin(), buf.end());
    std::istringstream iss(str);
    boost::archive::binary_iarchive ia(iss);

    Mango man;
    ia >> man;
    return man;
}

方案对比

  • 手动序列化:无外部依赖,速度最快,内存占用最低,但需手动处理所有类型,维护成本高;
  • Boost仅头文件:代码简洁,无需手动处理复杂容器,维护成本低,性能略逊于手动实现,但完全满足本地存储需求。

内容的提问来源于stack exchange,提问作者James_sheford

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:05:21