C++11中的POD
1.什么是POD?
C++11中的POD分为两部分的内容,包括Trival Type和Standard-layout。
A POD class is a class that is both trivial (can only be statically initialized) and standard-layout (has a simple data structure), and thus is mostly restricted to the characteristics of a class that are compatible with those of a C data structure declared with struct or union in that language, even though the expanded C++ grammar can be used in their declaration and can have member functions.1
所谓的POD类型就是满足Trival和Standard-layout的数据类型。可以方便地和C语言交互。当然可以适当的加上C++的某些特性,如:结构体和类中可以有函数等等。
2.什么是Trival Type?
A trivial type is a type whose storage is contiguous (trivially copyable) and which only supports static default initialization (trivially default constructible), either cv-qualified or not. It includes scalar types, trivial classes and arrays of any such types.2
Trival类型指的是:拥有线性存储空间,只支持静态默认初始化方式的,不论是否为const-volatile。它包括:scalar type(解释见上文),Trival类和该类型的数组。
2.1 如何判定Trival Type
A trivial class is a class (defined with class, struct or union) that is both trivially default constructible and trivially copyable, which implies that:
• uses the implicitly defined default, copy and move constructors, copy and move assignments, and destructor.
• has no virtual members.
• has no non-static data members with brace- or equal- initializers.
• its base class and non-static data members (if any) are themselves also trivial types. 3
第一条:uses the implicitly defined default, copy and move constructors, copy and move assignments, and destructor.
拥有默认的构造函数、析构函数、拷贝构造函数、移动构造函数、拷贝和移动赋值重载。即:我们不能够自定义任何上述的函数,即使函数体为空也不行,但是可以使用(=default)指出。
如图:Demo是TrivalType,但是Demox不是
第二条:has no virtual members
没有虚成员
第三条:has no non-static data members with brace- or equal- initializers
没有用(=或是{})赋默认值的非静态数据成员
如图:带有默认参数的结构体都不是TrivalType
第四条:• its base class and non-static data members (if any) are themselves also trivial types
它的基类和非静态数据成员也是Trival Type
如图:它是一个递归式的定义
3.什么是Standard-layout ?
3.1 Standard-layout(标准布局)的意义
A standard-layout type is a type with a simple linear data structure and access control that can easily be used to communicate with code written in other programming languages, such as C, either cv-qualified or not. This is true for scalar types, standard-layout classes and arrays of any such types.4
标准布局是拥有简单的线性存储空间和访问权限的类型,不管是否具有const-volatile属性,都可以非常方便地和用其他语言编写的代码(例如C语言)交互。标准布局或是拥有标准布局的数组都属于标量类型(scalar type)。
什么是scalar type?
A scalar type is a type that has built-in functionality for the addition operator without overloads (arithmetic, pointer, member pointer, enum and std::nullptr_t).5
标量类型是拥有语言内建的一些功能,而不需要重载的类型
3.2 如何判断标准布局
A standard-layout class is a class (defined with class, struct or union) that:
• has no virtual functions and no virtual base classes.
• has the same access control (private, protected, public) for all its non-static data members.
• 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.
• its base class (if any) is itself also a standard-layout class. And,
• has no base classes of the same type as its first non-static data member.
第一条:has no virtual functions and no virtual base classes
没有虚函数或是虚基类
(因为虚函数的实现依赖于虚函数表。)
第二条:has the same access control (private, protected, public) for all its non-static data members
对于所以非静态数据成员,他们的访问限制符都必须相同(private、protected、public)
如图所示:Demo中的a和b位于不同的访问控制当中,所以不是标准布局
第三条: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
1.在派生链最末端的派生类没有非静态数据成员并且在派生链最顶端的基类没有非静态数据成员。
2.或者,没有拥有非静态数据类型的基类。为什么?答:因为非静态数据类型存储在静态区,当我们sizeof一个类或结构体时,静态数据类型在这里是不计入该类或结构体的空间大小的。
如图:Demo是一个TrivalType,但是却不是标准布局,所以也就不是pod了。
第四条:its base class (if any) is itself also a standard-layout class
他的基类或它本身必须是一个标准布局
这是一个递归式的定义
第五条:has no base classes of the same type as its first non-static data member
没有于基类相同类型的变量作为成员。
看一段引用:
Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.6
不属于位域的两个对象可能拥有相同的地址(如果一个对象是另一个对象的子对象,或者至少有一个是空的基类子对象,并且他们的类型不同);否则,他们应该在不同的地址上。
情况一:当一个对象是另一个对象额子对象时
如上图,a是Demo对象d的子对象,他们位于同一个地址上
情况二:拥有一个空的基类,并且两个对象的类型不同时
通常情况下,派生类会在类的内部最前端建立一个基类的拷贝,虽然不可见,但是基类的拷贝的地址应该与派生类的地址相同。但是这里成员a的地址却和派生类地址相同。说明:C++优化将派生类于空基类共享内存,表明基类没有占据任何的内存空间。
试问:当“至少有一个是空的基类子对象,并且他们的类型不同”中的“类型不同”这一条件变为类型相同,会出现什么情况呢?
C++要求两个相同类型的对象必须位于不同的地址上。
所以,此时空基类将会占据1字节的空间,另一个成员将位于该类地址的后一个字节。
为什么上述的结构体不是标准布局?
A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.7
一个指向标准布局的结构体的指针,使用reinterpret_cast可以指向原始的成员(如果他的成员是一个位域,那么他将指向该成员所属的单元)反之亦然。
因此上述的结构体将引发兼容性问题,所以C++不将其列入标准布局的范畴。
- http://www.cplusplus.com/reference/type_traits/is_pod ↩
- http://www.cplusplus.com/reference/type_traits/is_trivial/ ↩
- http://www.cplusplus.com/reference/type_traits/is_trivial/ ↩
- http://www.cplusplus.com/reference/type_traits/is_standard_layout/ ↩
- http://www.cplusplus.com/reference/type_traits/is_standard_layout/ ↩
- http://stackoverflow.com/questions/11300439/standard-layout-c ↩
- http://stackoverflow.com/questions/11300439/standard-layout-c ↩