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

C++20实现Python多层字典结构及标准库二进制序列化方案

解决方案:Python多层字典转C++结构+标准库二进制序列化

一、C++对应数据结构设计

针对你描述的Python多层字典结构,C++中可以用**std::variant(变体类型)**结合std::map来实现类型匹配,同时保证键的稳定性:

#include <map>
#include <vector>
#include <variant>
#include <string>

// 底层值类型:整数、整数列表、int-int字典的变体
using TicTacToeValue = std::variant<int, std::vector<int>, std::map<int, int>>;
// 第二层字典:字符串键 -> 变体值
using TicTacToeSubDict = std::map<std::string, TicTacToeValue>;
// 第一层字典:字符串键 -> 第二层字典
using TicTacToeStateDict = std::map<std::string, TicTacToeSubDict>;
  • 用std::map而非std::unordered_map是为了保证键的有序性,序列化后结构更稳定;若追求性能,也可替换为unordered_map(C++20中std::string的哈希实现已标准化,无需额外处理)。
  • std::variant是C++17引入的类型,完美适配Python中同一键对应不同类型值的场景。

二、二进制序列化与反序列化(纯标准库实现)

C++标准库没有现成的二进制序列化工具,但可以基于std::ostream/std::istream手动实现,通过类型标签确保反序列化时的类型稳定性。

1. 序列化逻辑

#include <fstream>
#include <cstdint>
#include <stdexcept>

// 序列化整数
void serialize(std::ostream& os, int value) {
    const std::uint8_t type_tag = 0; // 标记当前值为int
    os.write(reinterpret_cast<const char*>(&type_tag), sizeof(type_tag));
    os.write(reinterpret_cast<const char*>(&value), sizeof(value));
}

// 序列化整数列表
void serialize(std::ostream& os, const std::vector<int>& vec) {
    const std::uint8_t type_tag = 1; // 标记当前值为vector<int>
    os.write(reinterpret_cast<const char*>(&type_tag), sizeof(type_tag));
    const std::size_t size = vec.size();
    os.write(reinterpret_cast<const char*>(&size), sizeof(size));
    for (int num : vec) {
        os.write(reinterpret_cast<const char*>(&num), sizeof(num));
    }
}

// 序列化int-int字典
void serialize(std::ostream& os, const std::map<int, int>& map_val) {
    const std::uint8_t type_tag = 2; // 标记当前值为map<int,int>
    os.write(reinterpret_cast<const char*>(&type_tag), sizeof(type_tag));
    const std::size_t size = map_val.size();
    os.write(reinterpret_cast<const char*>(&size), sizeof(size));
    for (const auto& pair : map_val) {
        os.write(reinterpret_cast<const char*>(&pair.first), sizeof(pair.first));
        os.write(reinterpret_cast<const char*>(&pair.second), sizeof(pair.second));
    }
}

// 序列化变体类型
void serialize(std::ostream& os, const TicTacToeValue& var) {
    std::visit([&os](const auto& val) {
        serialize(os, val);
    }, var);
}

// 序列化第二层字典
void serialize(std::ostream& os, const TicTacToeSubDict& sub_dict) {
    const std::size_t size = sub_dict.size();
    os.write(reinterpret_cast<const char*>(&size), sizeof(size));
    for (const auto& pair : sub_dict) {
        // 先序列化字符串键的长度,再序列化内容
        const std::size_t str_len = pair.first.size();
        os.write(reinterpret_cast<const char*>(&str_len), sizeof(str_len));
        os.write(pair.first.data(), str_len);
        // 序列化对应的值
        serialize(os, pair.second);
    }
}

// 序列化顶层字典
void serialize(std::ostream& os, const TicTacToeStateDict& state_dict) {
    const std::size_t size = state_dict.size();
    os.write(reinterpret_cast<const char*>(&size), sizeof(size));
    for (const auto& pair : state_dict) {
        const std::size_t str_len = pair.first.size();
        os.write(reinterpret_cast<const char*>(&str_len), sizeof(str_len));
        os.write(pair.first.data(), str_len);
        serialize(os, pair.second);
    }
}

// 保存到二进制文件的便捷函数
void save_tic_tac_toe_states(const std::string& file_path, const TicTacToeStateDict& states) {
    std::ofstream file(file_path, std::ios::binary);
    if (!file) {
        throw std::runtime_error("Failed to open file for writing");
    }
    serialize(file, states);
}

2. 反序列化逻辑

// 反序列化整数
int deserialize_int(std::istream& is) {
    int value;
    is.read(reinterpret_cast<char*>(&value), sizeof(value));
    return value;
}

// 反序列化整数列表
std::vector<int> deserialize_vector_int(std::istream& is) {
    std::size_t size;
    is.read(reinterpret_cast<char*>(&size), sizeof(size));
    std::vector<int> vec(size);
    for (std::size_t i = 0; i < size; ++i) {
        is.read(reinterpret_cast<char*>(&vec[i]), sizeof(vec[i]));
    }
    return vec;
}

// 反序列化int-int字典
std::map<int, int> deserialize_map_int_int(std::istream& is) {
    std::size_t size;
    is.read(reinterpret_cast<char*>(&size), sizeof(size));
    std::map<int, int> map_val;
    for (std::size_t i = 0; i < size; ++i) {
        int key, val;
        is.read(reinterpret_cast<char*>(&key), sizeof(key));
        is.read(reinterpret_cast<char*>(&val), sizeof(val));
        map_val[key] = val;
    }
    return map_val;
}

// 反序列化变体类型
TicTacToeValue deserialize_value(std::istream& is) {
    std::uint8_t type_tag;
    is.read(reinterpret_cast<char*>(&type_tag), sizeof(type_tag));
    switch (type_tag) {
        case 0: return deserialize_int(is);
        case 1: return deserialize_vector_int(is);
        case 2: return deserialize_map_int_int(is);
        default: throw std::runtime_error("Unknown type tag in variant");
    }
}

// 反序列化第二层字典
TicTacToeSubDict deserialize_sub_dict(std::istream& is) {
    std::size_t size;
    is.read(reinterpret_cast<char*>(&size), sizeof(size));
    TicTacToeSubDict sub_dict;
    for (std::size_t i = 0; i < size; ++i) {
        std::size_t str_len;
        is.read(reinterpret_cast<char*>(&str_len), sizeof(str_len));
        std::string key(str_len, '\0');
        is.read(&key[0], str_len);
        TicTacToeValue val = deserialize_value(is);
        sub_dict[key] = val;
    }
    return sub_dict;
}

// 反序列化顶层字典
TicTacToeStateDict deserialize_tic_tac_toe_states(std::istream& is) {
    std::size_t size;
    is.read(reinterpret_cast<char*>(&size), sizeof(size));
    TicTacToeStateDict state_dict;
    for (std::size_t i = 0; i < size; ++i) {
        std::size_t str_len;
        is.read(reinterpret_cast<char*>(&str_len), sizeof(str_len));
        std::string key(str_len, '\0');
        is.read(&key[0], str_len);
        TicTacToeSubDict sub_dict = deserialize_sub_dict(is);
        state_dict[key] = sub_dict;
    }
    return state_dict;
}

// 从二进制文件加载的便捷函数
TicTacToeStateDict load_tic_tac_toe_states(const std::string& file_path) {
    std::ifstream file(file_path, std::ios::binary);
    if (!file) {
        throw std::runtime_error("Failed to open file for reading");
    }
    return deserialize_tic_tac_toe_states(file);
}

三、使用示例

#include <iostream>

int main() {
    // 构建测试数据
    TicTacToeStateDict states;
    
    TicTacToeSubDict sub_dict1;
    sub_dict1["win_count"] = 5;
    sub_dict1["move_sequence"] = std::vector<int>{1,3,5};
    sub_dict1["score_map"] = std::map<int, int>{{0, 10}, {1, -5}};
    states["state_xxx"] = sub_dict1;
    
    // 保存与加载测试
    try {
        save_tic_tac_toe_states("tictactoe_states.bin", states);
        std::cout << "States saved successfully\n";
        
        TicTacToeStateDict loaded_states = load_tic_tac_toe_states("tictactoe_states.bin");
        std::cout << "Loaded " << loaded_states.size() << " states\n";
        
        // 访问加载的数据
        auto& loaded_sub = loaded_states["state_xxx"];
        if (std::holds_alternative<int>(loaded_sub["win_count"])) {
            std::cout << "Win count: " << std::get<int>(loaded_sub["win_count"]) << "\n";
        }
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
    }
    
    return 0;
}

四、关键注意事项

  1. 类型稳定性:type_tag的数值和顺序绝对不能随意修改,否则反序列化会直接失败。
  2. 跨平台兼容:如果需要在不同操作系统间传输文件,要处理字节序问题(可通过htonl/ntohl转换整数的字节序)。
  3. VS2022配置:确保项目启用C20标准(右键项目→属性→C/C→语言→选择ISO C20标准(/std:c20))。
  4. 性能适配:8533个状态的数据量很小,这套实现完全够用;若后续数据量增大,可优化为批量写入/读取逻辑。

内容的提问来源于stack exchange,提问作者Ξένη Γήινος

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:23:21