What is POD in C++?

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
2
template< class T >
struct is_standard_layout;
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <type_traits>

struct A {int m;};
struct B {
int m1;
private:
int m2;
};
struct C {virtual void foo();};

int main()
{
std::cout << std::boolalpha;
std::cout << std::is_standard_layout<A>::value << '\n';
std::cout << std::is_standard_layout<B>::value << '\n';
std::cout << std::is_standard_layout<C>::value << '\n';
}

// output
true
false
false

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct N { // neither trivial nor standard-layout
int i;
int j;
virtual ~N();
};
struct T { // trivial but not standard-layout
int i;
private:
int j;
};
struct SL { // standard-layout but not trivial
int i;
int j;
~SL();
};
struct POD { // both trivial and standard-layout
int i;
int j;
};

再考虑下面的代码:

1
2
3
4
5
6
7
8
9
10
struct s0{}; // is POD
struct s1{int a;}; // is POD
struct s2{int a;s2(int aa):a{aa}{}}; // not a POD (no default constructor)
struct S3 { int a; S3(int aa) : a(aa) { } S3() {} }; // a POD (user-defined default constructor)
struct S4 { int a; S4(int aa) : a(aa) { } S4() = default; }; // a POD
struct S5 { virtual void f(); /*...*/ }; // not a POD (has a virtual function)
struct S6 : S1 { }; // a POD
struct S7 : S0 { int b; }; // a POD
struct S8 : S1 { int b; }; // not a POD (data in both S1 and S8)
struct S9 : S0, S1 {}; //a POD

std::is_pod

可以使用std::is_pod来判断一个类型是否是POD类型。std::is_pod是一个标准库类型属性谓词,它定义在type_traits中,用法以及成员函数、成员类型与std::is_standard_layout相同。

1
2
template< class T >
struct is_pod;
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_pod<A>::value << '\n';
std::cout << std::is_pod<B>::value << '\n';
std::cout << std::is_pod<C>::value << '\n';
}

// output
true
false
false
全文完,若有不足之处请评论指正。

微信扫描二维码,关注我的公众号。

本文标题:What is POD in C++?
文章作者:查利鹏
发布时间:2016/12/03 00:04
本文字数:3.7k 字
原始链接:https://imzlp.com/posts/1140/
许可协议: CC BY-NC-SA 4.0
文章禁止全文转载,摘要转发请保留原文链接及作者信息,谢谢!
您的捐赠将鼓励我继续创作!