c++的std::is_trivially_copyable是什么意思? (影响memcpy性能)

std::is_trivially_copyable 是编译期布尔常量,用于判断类型T是否可被memcpy安全复制且语义等价于拷贝构造/赋值;仅当为true时才能安全替换为memcpy以获得性能提升。

std::is_trivially_copyable 是什么类型特征

它是一个编译期布尔常量,用于判断某个类型 T 是否满足「可被 memcpy 安全复制」的底层要求。不是“看起来能拷贝”,而是编译器保证:对该类型的对象做 memcpy,结果与调用其拷贝构造函数或赋值运算符**语义等价**。

为什么影响 memcpy 性能

std::is_trivially_copyable_vtrue,你才能安

全地把 std::copy 或手写循环替换成 memcpy —— 否则行为未定义。性能提升来自两方面:

  • memcpy 是编译器高度优化的内置操作,可能展开为单条 CPU 指令(如 rep movsb 或向量化指令)
  • 绕过构造/析构逻辑、虚表指针处理、成员函数调用开销

但注意:仅当类型满足 trivially copyable,且内存布局连续(如 std::vector 的 data())、对齐满足要求时,memcpy 才真正生效。

哪些类型通常不满足 trivially copyable

以下类型会让 std::is_trivially_copyable_v 返回 false,禁止直接 memcpy

  • 含非 trivial 拷贝构造函数、赋值运算符或析构函数的类(例如有 std::string 成员)
  • 含虚函数或虚基类的类(vptr/vtable 指针不能简单复制)
  • 含引用成员或 const 成员的类(复制后无法维持引用绑定或 const 语义)
  • 含用户定义的移动操作但未显式声明拷贝操作的类(可能隐式删除拷贝)
struct Bad {
    std::string s; // 非 trivial
    virtual void f() {} // 有虚函数
};

std::is_trivially_copyable_vfalse —— 对它的对象调用 memcpy 会破坏内部指针,引发崩溃或静默数据损坏。

怎么安全地用 memcpy 替代拷贝

必须同时验证三件事:

  • 类型是 trivially copyable:static_assert(std::is_trivially_copyable_v);
  • 源和目标内存不重叠(否则用 memmove
  • 地址对齐满足要求(尤其对 float/double/__m128 等)

典型安全用法:

template 
void fast_copy(T* dst, const T* src, size_t n) {
    static_assert(std::is_trivially_copyable_v, "T must be trivially copyable");
    memcpy(dst, src, n * sizeof(T));
}

最容易被忽略的是:即使 T 是 trivially copyable,若 T 包含指针(比如 struct { int* p; };),memcpy 只复制指针值,不复制它指向的数据 —— 这不是语言限制,而是语义设计,得你自己想清楚要不要深拷贝。