std::is_trivially_copyable 用于判断类型能否安全用 memcpy,要求所有成员和基类均为平凡可复制、无用户定义拷贝/移动函数、无虚函数或虚基类、析构函数为默认或删除;含 std::string 等非平凡类型则必为 false;即使为 true,仍需确保对齐、生命周期与内存权限合法。

std::is_trivially_copyable 用来判断能否安全用 memcpy
它返回 true,仅当类型满足:所有非静态成员和基类都是 trivially copyable;没有用户定义的拷贝/移动构造函数、赋值运算符;没有虚函数或虚基类;析构函数是默认或删除的。满足这些,才代表该类型的对象内存布局是“平坦”的,memcpy 不会跳过指针、不触发逻辑、不破坏内部状态。
常见误判场景:带 std::string 或 std::vector 的 struct
即使结构体只有两个 int 和一个 std::string,std::is_trivially_copyable_v 一定是 false。因为 std::string 内部有指针、容量、大小等字段,且其拷贝必须调用构造函数来管理堆内存 —— 直接 memcpy 会导致浅拷贝、双重释放或悬垂指针。
- 自定义类型中只要含任何标准容器、
std::shared_ptr、std::function,基本都不可 trivially copyable - 空类(
struct {})或纯 POD 结构(如struct { int x; double y; })通常是true - 有
constexpr构造函数但没用户定义拷贝函数,不影响 trivially copyable 判定
实际使用时别只查类型,还要看对象生命周期
即使 std::is_trivially_copyable_v 是 true,也不能无条件用 memcpy。比如:
- 对象包含未初始化的填充字节(padding),
memcpy会复制垃圾值(虽不崩溃,但可能影响 memcmp 或序列化一致性) - 目标内存未对齐(例如把
alignas(16)类型 memcpy 到char*数组起始处),会触发未定义行为 - 源或目标处于 const 限定或被
const_cast绕过的只读内存页上,memcpy可能 SIGSEGV
struct alignas(16) Vec4 { float x, y, z, w; };
static_assert(std::is_trivially_copyable_v); // ✅
Vec4 a = {1,2,3,4}, b;
memcpy(&b, &a, sizeof(Vec4)); // ❌ 若 &b 未按 16 字节对齐,UB
替代方案:优先用 = default 拷贝,而非 memcpy
现代 C++ 中,99% 的场景下,编译器对 T a = b; 或 std::copy 的优化程度和 memcpy 一样高,且语义安全。只有在极少数底层场景(如 ring buffer 批量搬运、与 C ABI 交互、GPU 显存映射)才需手动 memcpy,此时必须同时检查:
立即学习“C++免费学习笔记(深入)”;
-
std::is_trivially_copyable_v为true -
std::is_standard_layout_v(保证内存布局可预测,避免基类偏移问题) - 源/目标地址满足
alignof(T)对齐要求 - 确认没有跨线程共享或正在析构的对象参与 memcpy
漏掉其中任一条件,就不是“能 memcpy”,而是“正在制造难以复现的崩溃”。









