直接用std::ofstream::write写含指针或stl成员的c++对象会失败,因只保存地址而非实际数据,反序列化后导致悬空指针、vptr错乱、内容丢失;pod结构跨平台/编译器也不安全,必须显式序列化逻辑。

因为直接用 std::ofstream::write 写一个含指针的 C++ 对象,写进去的只是指针变量本身的 8 字节(或 4 字节)地址值,不是它指向的那块内存里的数据;反序列化时读出来的还是这个旧地址,但那块内存早已释放或被覆盖——程序立刻崩溃或读出垃圾值。
std::string、std::vector 这类成员一写就错
它们内部都存着指针(比如 std::string 的 _M_dataplus._M_p),sizeof 只算结构体头大小,不包含堆上实际字符串内容。你写进去的是一串随机地址,读出来后调用 .c_str() 就段错误。
- 哪怕对象看起来“没显式写指针”,只要用了任何 STL 容器、
std::shared_ptr、std::unique_ptr,就不能裸拷贝 -
std::vector的size()和capacity()也不等于它实际占用的字节数,直接write会漏掉元素数据 - 虚函数表(vptr)位置和内容由编译器决定,跨平台/版本无法保证一致,memcpy 后对象无法安全调用虚函数
Mat.data 指针不能 memcpy 的真实原因
OpenCV 的 cv::Mat 不是 POD:它的 data 是裸指针,step 是每行字节数,refcount 是引用计数指针,还有 ROI 偏移。只拷 sizeof(Mat),得到的是一个悬空的壳子,data 指向的位置可能已被其他 Mat 共享或释放。
- 序列化必须显式保存
rows、cols、type()、step和整块data字节数组(用total() * elemSize()算) - 反序列化时不能直接构造
Mat,得用Mat(rows, cols, type, data_ptr)或先create()再memcpy -
FileStorage(XML/YAML/JSON)能自动处理这些,但体积大、慢;手动二进制快,但必须自己管好头+数据+对齐
POD 类型也别轻易用 sizeof(obj) 写文件
所谓“纯 struct”只要加了 std::string 就不再是 POD;即使全是 int/double,不同编译器、不同对齐设置(#pragma pack)、不同平台(x86 vs ARM)下 sizeof 和成员偏移都可能不同。
- 比如一个
struct { int a; double b; },在 MSVC 默认对齐下sizeof是 16,GCC 可能是 12 —— 直接读会错位 - 没有版本号字段的话,后续加个字段就全盘解析失败,且毫无提示
- 网络传输更危险:大小端不统一,
int32_t写进去是小端,读的一方是大端,值就全乱
真正安全的序列化,永远要从“这个对象有哪些逻辑状态”出发,而不是“它占多少字节”。哪怕只是多写两个 uint32_t 记长度、用 htonl 统一端序、把 std::string 拆成“长度+字符数组”,都比赌 sizeof 强。最省事的方案不是手写,而是用 nlohmann::json 或 boost::serialization——它们早把指针、容器、继承、版本兼容这些坑踩平了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











