反序列化时直接用裸指针接收数据危险,因其不管理内存生命周期,易导致越界访问、解引用非法地址、跨平台失败等问题;应改用placement new配合显式析构,或优选智能指针封装工厂函数。

反序列化时直接用裸指针接收数据为什么危险
裸指针本身不管理内存生命周期,反序列化过程若需动态构造对象(比如从字节流还原 std::vector、嵌套结构体或字符串),用 int* 或 MyStruct* 硬接原始内存,极易触发未定义行为:读越界、写到只读段、或把字节流误当指针值解引用。
常见错误现象包括:Segmentation fault、double free、字段值异常(如字符串首地址变成 0x0000ffff)、以及跨平台反序列化失败(因结构体对齐/大小不一致)。
- 别把网络字节流 memcpy 到栈上局部
MyClass*指向的地址——栈空间没预留足够大小,也无构造逻辑 - 别用
reinterpret_cast<myclass>(buf)</myclass>强转后直接调用成员函数——类可能含虚表、非POD成员,该操作不合法 - 若 buf 来自 malloc 或 new[],记得反序列化后显式 delete[],且必须确保布局与序列化端完全一致(建议加
static_assert(std::is_standard_layout_v<myclass>)</myclass>)
用 placement new + 显式析构替代裸指针分配
当你确实需要在已有内存块上“复活”对象(例如共享内存、预分配缓冲区场景),应跳过 new,改用 placement new,并手动管理生命周期。
char buffer[sizeof(Person) + 256]; // 预留足够空间 Person* p = new (buffer) Person(); // 调用构造函数 // ... 反序列化字段:p->id = read_int(buf); p->name = std::string(read_cstr(buf + 4)); // 使用完毕后必须显式析构 p->~Person();
关键点:
- placement new 不分配内存,只调用构造函数;必须确保
buffer地址对齐(alignas(Person)更安全) - 反序列化字段时,不能依赖
memcpy整体拷贝——非 trivially copyable 类型(含std::string、std::vector)必须逐字段解析并构造 - 析构必须显式调用,否则资源泄漏(如
std::string内部堆内存不释放)
更安全的做法:用智能指针 + 工厂函数封装反序列化逻辑
绝大多数场景下,应避免裸指针参与反序列化流程。用 std::unique_ptr 承载所有权,配合工厂函数隔离内存分配与解析细节。
std::unique_ptr<person> DeserializePerson(const uint8_t* data, size_t len) {
if (len ();
p->id = *reinterpret_cast<const uint32_t>(data);
uint8_t name_len = data[4];
if (len name.assign(reinterpret_cast<const char>(data + 5), name_len);
return p;
}
</const></const></person>
这样做的好处:
- 调用方无需关心
delete,也不会误用野指针 - 工厂内部可插入校验(长度、magic number、CRC)、版本兼容处理
- 便于替换底层实现(如改用 Protocol Buffers 或 JSON 解析时,接口不变)
指针字段在反序列化中要单独处理
如果结构体本身含指针成员(如 char* name),它在序列化时通常只存了地址值,而非真实内容——这在跨进程/跨机器时必然失效。必须约定协议:指针字段一律按“长度+数据”方式序列化。
例如这个结构体:
struct BadExample {
int id;
char* data; // ❌ 反序列化后指向随机地址
};
正确做法是改为:
struct GoodExample {
int id;
std::vector<uint8_t> data; // ✅ 可直接序列化 .size() 和 .data()
};
// 或者用 length-prefixed raw buffer:
// [uint32_t len][uint8_t[len]]
</uint8_t>
- 永远不要序列化裸指针值;所有动态数据必须内联存储或通过独立字段描述偏移/长度
- 若必须保留 C 风格接口(如返回
const char*),应在反序列化函数内部分配内存,并由调用方负责free——但此时务必文档注明,且比智能指针方案更容易出错
反序列化里最常被忽略的不是语法,而是“谁拥有这块内存、何时释放、内容是否真正可迁移”。裸指针在这里不是捷径,是陷阱入口。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











