memcpy复制对象的前提是类型必须为trivially copyable,即std::is_trivially_copyable_v为true;否则行为未定义,可能导致悬垂指针、双重释放等问题。

memcpy 复制对象的前提:必须是 trivially copyable 类型
直接用 memcpy 复制 C++ 对象是危险的,除非该类型满足 std::is_trivially_copyable_v<t></t> 为 true。否则行为未定义——比如含虚函数、非平凡构造/析构、引用成员、std::string 成员的对象,memcpy 会跳过构造逻辑,导致悬垂指针、资源重复释放或内存泄漏。
常见可安全 memcpy 的类型包括:POD 结构体、C 风格 struct、std::array<int></int>、std::vector 的底层数据(但不是 vector 对象本身)、原始数组。
- 检查方式:
static_assert(std::is_trivially_copyable_v<mystruct>);</mystruct> - 错误示例:
memcpy(&dst, &src, sizeof(MyClassWithString));——std::string内部有指针,浅拷贝后两个对象指向同一堆内存 - 替代方案:优先用拷贝构造或赋值运算符;若确需字节拷贝(如序列化、GPU 内存传输),先确认类型可平凡复制
正确调用 memcpy 的三个参数顺序和长度计算
memcpy 原型是 void* memcpy(void* dest, const void* src, size_t n),最容易错的是第三个参数:它要求传入**字节数**,不是元素个数,也不是 sizeof(T)(除非只拷一个)。
- 拷单个对象:
memcpy(&dst, &src, sizeof(src));或sizeof(MyStruct) - 拷数组(5 个 int):
memcpy(dst_arr, src_arr, 5 * sizeof(int));,不能写sizeof(src_arr)(若 src_arr 是指针则失效) - 避免用
sizeof作用于指针变量——它返回指针大小(通常 8),而非所指内容大小 - 目标内存必须已分配且足够大;
memcpy不做越界检查,溢出时静默破坏相邻内存
memcpy vs 拷贝构造:什么时候不该用 memcpy
即使类型是 trivially copyable,也未必该用 memcpy。它的本质是字节覆盖,绕过了所有语义逻辑。
- 含 std::unique_ptr 成员的结构体?虽然可能是 trivially copyable(取决于编译器和标准版本),但 memcpy 会让两个对象持有相同裸指针,析构时 double-free
- 需要深拷贝语义时(如自定义资源管理),必须走构造函数,
memcpy无法触发任何用户代码 - 调试困难:
memcpy后对象看似“正常”,但某些字段(如 padding 区域)可能被意外修改,引发偶发崩溃 - 现代 C++ 中,
std::copy或范围 for 更安全可读;只有在性能敏感且确认无副作用的场景(如 memcpy 一块对齐的 raw buffer)才考虑
替代 memcpy 的更安全选择:std::bit_cast(C++20)和 std::memcpy 的封装
C++20 引入 std::bit_cast,适用于类型间无损重解释(如 float ↔ uint32_t),但它要求源目类型大小严格相等且都 trivially copyable,且不支持对象内布局依赖(如 bit-field)。
若仍需 memcpy 行为,建议封装一层带静态断言的工具函数:
template<typename t>
void safe_memcpy(T& dst, const T& src) {
static_assert(std::is_trivially_copyable_v<t>, "T must be trivially copyable");
memcpy(&dst, &src, sizeof(T));
}</t></typename>
这样既保留 memcpy 效率,又把检查前移到编译期。注意:不能用于含 padding 变量的结构体跨平台传输(不同编译器 padding 可能不同)。
真正棘手的地方不在语法,而在判断“这个 struct 真的没隐藏状态吗”——比如某个看似简单的 struct 里,某天加了个 std::function 成员,整个 memcpy 调用就悄然失效了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











