如何检测可通过memcpy赋值的类型?(tuple、pair)
判断可通过memcpy替代赋值的类型:std::is_trivially_copyable
嘿,这个问题问到点子上了!你要找的正是C++标准定义的**可平凡复制(trivially copyable)**类型——这类类型的赋值操作完全可以安全地用memcpy或类似的原始内存拷贝操作替代,而且是标准保证合法的。
核心type_trait:std::is_trivially_copyable
C++11及以后提供了std::is_trivially_copyable<T>这个类型特征(位于<type_traits>头文件),它会在编译期返回true当且仅当类型T满足以下条件:
- 拥有平凡的复制构造函数(即默认生成,无用户自定义逻辑,也无虚函数/虚基类)
- 拥有平凡的移动构造函数
- 拥有平凡的复制赋值运算符
- 拥有平凡的移动赋值运算符
- 拥有平凡的析构函数
- 类型不是抽象类(无纯虚函数),也不包含非平凡的成员/基类
符合条件的常见类型示例
你提到的这些类型都属于可平凡复制范畴:
- 所有内置类型:
int、double、char、bool等 - 由可平凡复制类型组成的
std::tuple(包括嵌套tuple) - 成员均为可平凡复制类型的普通结构体/联合体(且自身的特殊成员函数都是默认生成的)
- 可平凡复制类型的数组(比如
int[5]、std::tuple<int, double>[10])
举个代码验证的例子:
#include <type_traits> #include <tuple> #include <array> // 自定义平凡结构体 struct PlainData { int id; double value; }; int main() { // 内置类型验证 static_assert(std::is_trivially_copyable<int>::value, "int should be trivially copyable"); // tuple验证 using NestedTuple = std::tuple<PlainData, std::tuple<char, long>>; static_assert(std::is_trivially_copyable<std::tuple<int, double>>::value, "Tuple of trivials is trivially copyable"); static_assert(std::is_trivially_copyable<NestedTuple>::value, "Nested tuple is trivially copyable"); // 数组验证 static_assert(std::is_trivially_copyable<std::array<PlainData, 3>>::value, "Array of trivials is trivially copyable"); return 0; }
注意区分容易混淆的类型特征
std::is_pod<T>:这是C早期的类型特征,条件比is_trivially_copyable更严格(还要求类型是可平凡默认构造的),C17已弃用。如果你只关心能否用memcpy拷贝,is_trivially_copyable是更精准的选择——比如一个有自定义非平凡默认构造函数但其他特殊成员都是平凡的类型,不是POD,但依然可以安全用memcpy拷贝。std::is_trivial<T>:这个要求类型的所有特殊成员函数都是平凡的,包括默认构造函数,同样比is_trivially_copyable严格,不符合你的需求场景。
关键注意事项
即使类型是可平凡复制的,也要确保拷贝的对象处于有效状态:比如拷贝指针类型时,memcpy只会拷贝指针本身的地址值,而不会拷贝指针指向的动态内存(这本身符合指针的语义,但如果你需要深拷贝,那指针类型显然不适合直接用memcpy)。而像std::string、std::vector这类非平凡复制类型,绝对不能用memcpy拷贝,因为它们内部管理着动态资源,直接拷贝内存会导致双重释放等未定义行为。
内容的提问来源于stack exchange,提问作者alfC
相关产品推荐
相关产品推荐

