有风险,且很常见;非pod结构体(含指针、std::string、虚函数表等)用write()会写入无效地址导致崩溃,仅纯pod结构体可安全二进制序列化。

直接用 write() 写结构体有风险吗?
有,而且很常见。如果结构体含指针、std::string、std::vector 或虚函数表(即非 POD 类型),write() 二进制 dump 会把指针地址写进去,读取时必然崩溃或数据错乱。
只有纯 POD(Plain Old Data)结构体才可安全 memcpy:
-
struct Point { int x; int y; };✅ 可直接write() -
struct Person { std::string name; int age; };❌ 不行,name是堆上管理的字符串 -
struct Base { virtual void f() {} };❌ 含虚表,sizeof不等于成员总和
POD 结构体怎么安全二进制序列化?
确认是 POD 后,用 std::ofstream::write() 最快最直接:
struct Config {
int version;
double timeout;
char mode[16];
};
static_assert(std::is_pod_v<Config>, "Config must be POD");
Config cfg = {1, 3.5, "auto"};
std::ofstream ofs("config.bin", std::ios::binary);
ofs.write(reinterpret_cast<const char*>(&cfg), sizeof(cfg));
读取时注意:必须保证编译器对齐一致(建议加 #pragma pack(1) 或用 alignas 显式控制);跨平台时还要考虑字节序(x86 是小端,网络传输需转大端)。
立即学习“C++免费学习笔记(深入)”;
含 std::string 的结构体怎么序列化?
必须手动处理:先写字符串长度(size_t),再写字符内容。读取时先读长度,再按长度分配并读取:
struct Message {
std::string text;
int id;
};
std::ofstream ofs("msg.bin", std::ios::binary);
size_t len = msg.text.size();
ofs.write(reinterpret_cast<const char*>(&len), sizeof(len));
ofs.write(msg.text.data(), len);
ofs.write(reinterpret_cast<const char*>(&msg.id), sizeof(msg.id));
反序列化时顺序严格对应,且要检查 len 是否过大(防内存爆炸);std::string::data() 在 C++17 后保证以 \0 结尾,但二进制序列化通常不依赖空终止符。
有没有更通用、少出错的方案?
用 boost::serialization 或 cereal 这类库,它们自动处理类型、版本、容器嵌套和指针间接性。例如 cereal 只需加一个 serialize() 成员:
struct Person {
std::string name;
int age;
template <class Archive>
void serialize(Archive& ar) {
ar(CEREAL_NVP(name), CEREAL_NVP(age));
}
};
然后:cereal::BinaryOutputArchive ar(ofs); ar(p); —— 库内部已处理字符串长度、对齐、字节序兼容等细节。
不过引入第三方库会增加构建复杂度;若仅需轻量级、单平台、固定结构,手写二进制 I/O 更可控——关键是要清楚每字节的含义,别让 sizeof 欺骗你。











