在C++11中,平凡类型(Trivial Type)、平凡可复制类型(TrivialCopyable)、标准布局类型(Standard-layout Type)
是描述类在内存中布局特性的术语,它们与类的构造、拷贝、赋值和销毁行为有关,也影响着类的内存布局和对齐方式。
下面用通俗的语言解释这些概念:
平凡类型
指那些在内存中的行为非常简单的类。它们的构造函数、析构函数、拷贝构造函数和赋值运算符都没有自定义实现,
完全由编译器提供的默认行为即可,而且也不能包含虚函数以及是虚基类的父类, 这意味着这些类的对象可以像基本
数据类型一样被创建和销毁,不需要特殊的资源管理代码。
#include <iostream> #include <type_traits>// 平凡类型:没有任何自定义的构造函数、析构函数、拷贝控制成员 struct TrivialType {int a;double b; };// 非平凡类型:至少有一个自定义的特殊成员函数 struct NonTrivialType1 {int a;double b;// 自定义构造函数NonTrivialType1() : a(0), b(0.0) {}// 自定义拷贝赋值运算符NonTrivialType1& operator=(const NonTrivialType1& other) {a = other.a;b = other.b;return *this;}// 自定义析构函数~NonTrivialType1() {std::cout << "NonTrivialType1 destroyed\n";} };//使用=default关键字可以显式地声明默认的构造函数,从而使得类型恢复 “平凡化”。 struct TrivialType2 {int a;double b;// 自定义构造函数TrivialType2(int a, double b) : a(a), b(b) {}TrivialType2() = default; };int main() {TrivialType t1, t2;t2 = t1; // 平凡类型的赋值操作是平凡的 NonTrivialType nt1, nt2;nt2 = nt1; // 非平凡类型的赋值操作不是平凡的 std::cout << "TrivialType is is_trivial:" << std::is_trivial<TrivialType>::value << std::endl; //输出:truestd::cout << "NonTrivialType1 is is_trivial:" << std::is_trivial<NonTrivialType1>::value << std::endl; //输出:false std::cout << "TrivialType2is is_trivial:" << std::is_trivial<TrivialType2>::value << std::endl; //输出: truereturn 0; }
注意事项:
即使类没有显示定义特殊成员函数,如果类中有虚函数或虚基类,它也不是平凡类型。
类中如果有动态内存分配(如指针成员)或需要特殊资源管理的成员,也不是平凡类型。
平凡类型的所有特殊成员函数都是平凡的,这意味着它们可以没有函数体(即使用编译器提供的默认实现)。
平凡类型在C++中很重要,因为它们可以提高效率,允许编译器进行更多的优化。例如,平凡类型的拷贝和赋值可以通过简单的内存复制完成,而不需要调用任何成员函数。
平凡可复制类型
是平凡类型的一个扩展,它不仅包括所有平凡类型,还包括那些可以安全地被复制和移动的类型,即使这些类型不是平凡类型。例如,一个类可能有一个自定义的构造函数,但如果它保证对象的内容可以通过简单的位拷贝(bitwise copy)来复制,那么它也可以被认为是平凡可复制的。它必须满足两个条件:
类型可以被复制或移动,且不需要特殊的资源管理。
类型的所有特殊成员函数(构造函数、拷贝构造函数、移动构造函数、赋值运算符、移动赋值运算符和析构函数)都是平凡的或者被删除的(deleted)。
下列类型统称为可平凡复制类型:
标量类型
可平凡复制类类型
上述类型的数组
这些类型的有 cv 限定版本
说明:
一般来说,对于任何可平凡复制类型 T 及 T 对象 obj1,能复制 obj1 的底层字节到 char 或 unsigned char 或 std::byte (C++17 起) 的数组中,或到 T 的另一不同对象 obj2 中。obj1 与 obj2 均不可为潜在重叠的子对象。
如果复制 obj1 的底层字节到这种数组中,然后复制结果内容回 obj1 中,那么 obj1 将保有其原值。如果复制 obj1 的底层字节到 obj2 中,那么 obj2 将保有 obj1 的值。
底层字节能由 std::memcpy 或 std::memmove 复制,只要不访问存活的 volatile 对象即可。
标准布局类型
指那些在内存布局上满足一定规则的类。这些规则包括所有非静态成员的访问权限必须相同,类不能有虚函数或虚基类,且所有基类也必须是标准布局类型。标准布局类型的一个重要特性是它们的内存布局在不同的编译器和平台上是一致的,这对于跨平台的二进制数据交换非常重要,它必须满足以下条件:
1)类型的所有非静态数据成员都是公共的(public)。
2)类型不包含虚函数、虚基类或非标准布局的基类。
3)类型的所有基类都是标准布局类型。
4)类型不包含动态内存分配,如没有指向其自身类型的指针成员。
5)类型的所有数据成员的访问权限(public、protected、private)都是相同的。
#include <iostream> #include <type_traits> // For std::is_standard_layout// 标准布局类型:没有任何虚函数或虚基类,所有数据成员都是公共的 struct StandardLayoutType {int a;double b; };// 非标准布局类型:包含虚函数 struct NonStandardLayoutTypeWithVirtualFunction {virtual void dummy() {}int a;double b; };// 非标准布局类型:包含非标准布局基类 struct NonStandardBase {int a; protected:double b; // Data member with non-public access };struct NonStandardLayoutTypeWithNonStandardBase : NonStandardBase {int c; };// 标准布局类型:尽管有继承,但基类是非虚继承且本身也是标准布局 struct StandardLayoutTypeWithInheritance : StandardLayoutType {char c; };int main() {std::cout << std::boolalpha; // Print bool values as true/false// 检查是否为标准布局类型std::cout << "Is StandardLayoutType standard layout? " << std::is_standard_layout<StandardLayoutType>::value << std::endl;std::cout << "Is NonStandardLayoutTypeWithVirtualFunction standard layout? " << std::is_standard_layout<NonStandardLayoutTypeWithVirtualFunction>::value << std::endl;std::cout << "Is NonStandardLayoutTypeWithNonStandardBase standard layout? " << std::is_standard_layout<NonStandardLayoutTypeWithNonStandardBase>::value << std::endl;std::cout << "Is StandardLayoutTypeWithInheritance standard layout? " << std::is_standard_layout<StandardLayoutTypeWithInheritance>::value << std::endl;return 0; }
C++ STL的std::is_trivially_copyable模板用于检查T是否为平凡可复制的类型(存储连续的类型)。
这类类型具有以下特征:
定义与用途
平凡可复制类型指那些无需特殊拷贝或移动操作即可完成完整复制的类型,其复制操作可视为位级复制(bitwise copy)。例如:
内置类型(如 int、double)
数组类型(如 int)
使用默认构造函数/析构函数的类(如未自定义特殊成员函数的类)
#include<type_traits> std::is_trivially_copyable<T>::value //参数:模板std::is_trivially_copyable接受单个参数T(Trait类),以检查T是否是平凡可复制的类型。
如果T是平凡可复制的类型,则它返回布尔值true,否则返回false。
参考:
C++ std::is_trivially_copyable模板用法及代码示例
C++之std::is_trivially_copyable(平凡可复制类型检测)