最直接可控的序列化方式是手动用std::ostringstream拼接:显式访问成员、避免operator<<污染、注意浮点精度与字符串转义。

用 std::ostringstream 手动拼接最直接
没有反射,C++ 原生不支持自动序列化,最可控的方式是自己写格式化逻辑。适合结构简单、字段固定、对可读性有要求的场景(比如日志、调试输出)。
关键点:别依赖 operator<< 的全局重载——它可能被第三方库污染或未定义;显式调用成员变量,避免隐式转换陷阱。
- 用
std::ostringstream而非std::string拼接,避免多次内存分配 - 数字转字符串时注意精度,
os << std::fixed << std::setprecision(6) << value可控但需<iomanip> - 字符串成员要处理引号和转义,比如
os << """ << str.c_str() << """,否则含空格或换行会破坏结构
struct Point {
double x, y;
std::string name;
std::string to_string() const {
std::ostringstream os;
os << "{x:" << x << ",y:" << y << ",name:"";
// 简单转义双引号(仅示例,生产环境建议用更健壮的 escape)
for (char c : name) {
if (c == '"') os << "\"";
else os << c;
}
os << ""}";
return os.str();
}
};
用 json.hpp(nlohmann/json)快速生成 JSON 字符串
当目标是通用、可解析、带嵌套结构的字符串时,引入轻量 JSON 库是最省心的选择。它不依赖宏或代码生成,头文件即用,且对 STL 容器天然友好。
常见错误:直接传 this 或未声明 to_json,导致编译失败或空对象。
立即学习“C++免费学习笔记(深入)”;
- 必须在命名空间内定义
void to_json(nlohmann::json&, const YourType&),不能是成员函数 - 枚举需显式转为整数或字符串,
json["type"] = static_cast<int>(e) - 若含指针成员,必须判空再序列化,否则解引用崩溃
- 性能敏感场景慎用:JSON 序列化涉及动态内存分配和字符串拷贝,比纯二进制慢一个数量级
#include <nlohmann/json.hpp>
using json = nlohmann::json;
struct Config {
int timeout;
std::vector<std::string> hosts;
};
void to_json(json& j, const Config& c) {
j = json{{"timeout", c.timeout}, {"hosts", c.hosts}};
}
// 使用:
Config cfg{30, {"127.0.0.1", "localhost"}};
std::string s = json(cfg).dump(); // → {"timeout":30,"hosts":["127.0.0.1","localhost"]}
用 std::stringstream + 自定义分隔符做 CSV 风格序列化
当数据要导入 Excel 或下游是 Python pandas 时,CSV 比 JSON 更轻量。但 C++ 标准库无 CSV 支持,得自己控制字段分隔与引号规则。
最容易踩的坑是没按 RFC 4180 处理含逗号、换行、双引号的字段——Excel 会错行或截断。
- 只要字段含
,、"或换行符,就必须用双引号包裹 - 字段内双引号要替换成两个双引号(
"→""),不是反斜杠转义 - 不要手写
os << """ << field << """—— 先判断是否需要包裹,再统一 escape - 二进制数据(如
std::vector<uint8_t>)不适合 CSV,应转 base64 或跳过
std::string csv_escape(const std::string& s) {
bool needs_quote = s.find_first_of(","
") != std::string::npos;
if (!needs_quote) return s;
std::string out = """;
for (char c : s) {
if (c == '"') out += """"; // RFC 4180 规则
else out += c;
}
out += """;
return out;
}
为什么不该用 memcpy 或 reinterpret_cast 直接转内存
看到“序列化”就想到二进制拷贝?这在 C++ 里几乎总是错的。成员变量布局受对齐、填充、虚函数表、字节序影响,跨平台或升级编译器后必然失效。
典型症状:std::string 成员序列化后变成乱码地址,std::vector 只存了指针而非数据,bool 在不同平台占 1 字节还是 4 字节不确定。
- POD 类型(仅含基本类型、无构造/析构/虚函数/非静态成员)才可能安全 memcpy,但仍需
static_assert(std::is_pod_v<T>)保证 - 即使 POD,
#pragma pack(1)和默认对齐混用会导致结构体大小不一致 - 网络传输必须考虑字节序,
htonl/ntohl仅对整数有效,浮点数无标准网络序
真要二进制序列化,请用 Protocol Buffers 或 Cap’n Proto 这类有 schema 和跨语言支持的方案,而不是自己 reinterpret_cast。


















