POD is Plain Old Data(普通旧数据).在C++中是指能被“仅当作数据”处理的对象,程序员无暇顾及类布局的复杂性以及用户自定义的构造、拷贝和移动语义。
在介绍什么是POD之前,应该先了解一下以下几个概念。
Scalar types
Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types.
standard-layout types
Scalar types, standard-layout class types (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called standard-layout types.(ISO/IEC 14882:2014(E) §3.9.1 P71)
standard-layout class
A standard-layout class is a class that:
- has no non-static data members of type non-standard-layout class (or array of such types) or reference,
- has no virtual functions (10.3) and no virtual base classes (10.1),
- has the same access control (Clause 11) for all non-static data members,
- has no non-standard-layout base classes,
- either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
- has no base classes of the same type as the first non-static data member.(This ensures that two subobjects that have the same class type and that belong to the same most derived object are not allocated at the same address)
通俗点来说一个类型具有标准布局,不应该具有以下几种性质:
- 含有一个非标准布局的非static成员或基类
- 包含virtual函数
- 包含virtual基类
- 含有引用类型的成员
- 其中的非static数据成员有多种访问修饰符(public/private/protected)
- 阻止重要的布局优化
- 在多个基类中含有非static数据成员,或者在派生类和基类中都含有非static数据成员
- 基类类型与第一个非static数据成员类型相同
基本上,标准布局类型是指与C语言的布局兼容的类型,并且应该能被常规的C++ ABI(应用程序二进制接口)处理。
std::is_standard_layout
标准库中有std::is_standard_layout
可以判断一个类型是否为标准布局,它定义在type_traits
中。
1 | template< class T > |
Member constants | |
---|---|
value [static] | true if T is a standard-layout type type , false otherwise |
Member functions | |
operator bool | converts the object to bool , returns value (public member function) |
operator() (C++14) | returns value (public member function) |
Member types | |
Type | Definition |
value_type | bool |
type | std::integral_constant<bool , value > |
1 |
|
trivially copyable types
Cv-unqualified scalar types, trivially copyable class types (Clause 9), arrays of such types, and non-volatile const-qualified versions of these types (3.9.3) are collectively called trivially copyable types.(ISO/IEC 14882:2014(E) §3.9.1 P71)
trivially copyable class
A trivially copyable class is a class that:
- has no non-trivial copy constructors (12.8),
- has no non-trivial move constructors (12.8),
- has no non-trivial copy assignment operators (13.5.3, 12.8),
- has no non-trivial move assignment operators (13.5.3, 12.8), and
- has a trivial destructor (12.4).
A trivial class is a class that has a default constructor (12.1), has no non-trivial default constructors,and is trivially copyable.[ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. — end note ] (ISO/IEC 14882:2014(E) §9 P215)
除非在类型内部含有non-trivial的拷贝、移动或者析构,否则该类型就是平凡可拷贝的类型(trivially copyable type)。
内置类型的变量都是平凡可拷贝的,且拥有标准布局。同样,由平凡可拷贝对象组成的数组是平凡可拷贝的,由标准布局对象组成的数组拥有标准布局。
POD types
Scalar types, POD classes(Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types.
POD必须属于下列类型的对象:
- 标准布局类型(standard-layout types)
- 平凡可拷贝类型(trivially copyable type)
即如果我们想把某个对象”仅当做数据“处理(POD),则要求该对象必须满足下述条件:
- 不具有复杂的布局(比如含有vptr)
- 不具有非标准(用户自定义)的拷贝语义
- 含有一个最普通(trivial)的默认构造函数
trivial default constructor:a default constructor is trivial if it does not need to do any work (use =default if you need to define one).(TC++PL4E(E) §8.2.6 P211)
需要注意的是,增加或删除非默认构造函数不会影响布局和性能(在C++98中不是这样)。
A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). Similarly, a POD union is a union that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). A POD class is a class that is either a POD struct or a POD union.(ISO/IEC 14882:2014(E)§9.1 P216)
1 | struct N { // neither trivial nor standard-layout |
再考虑下面的代码:
1 | struct s0{}; // is POD |
std::is_pod
可以使用std::is_pod
来判断一个类型是否是POD类型。std::is_pod
是一个标准库类型属性谓词,它定义在type_traits
中,用法以及成员函数、成员类型与std::is_standard_layout
相同。
1 | template< class T > |
1 | int main() |