深入理解C++11 3.6 POD类型

POD全程Plain Old Data。C++11将POD划分为两个基本概念的集合,即:平凡的(trivial)和标准布局的(standard layout)。

平凡的类或者结构体应该符合以下定义:
1)拥有平凡的默认构造函数和析构函数
平凡的构造函数和析构函数的意思是函数什么都不做。通常情况下,不定义构造函数编译期会生成一个平凡的默认构造函数。而一旦定义了构造函数,即使函数不包含参数,函数体没有代码,那么该构造函数也不再是”平凡“的。但可以通过”=default“关键字显示声明缺省版本的构造函数,使得类型”平凡化“
2)拥有平凡的拷贝构造函数和移动构造函数。平凡的拷贝构造函数等同于使用memcpy进行类型的构造。同样可以使用”=default“声明默认拷贝构造函数。平凡移动构造函数和拷贝构造函数类似,用于移动语义
3)拥有平凡的拷贝赋值运算符和移动赋值运算符
4)不能包含虚函数和虚基类

C++11中可以通过类模板进行判断

template  struct std::istrivial;

以下是个例子

#include 

using namespace std;

struct Trivial1 {};

struct Trivial2 {
public:
    int a;
private:
    int b;
};

struct Trivial3 {
    Trivial1 a;
    Trivial2 b;
};

struct Trivial4 {
    Trivial2 a[23];
};

struct Trivial5 {
    int x;
    static int y;
};

struct NonTrivial1 {
    NonTrivial1() : z(42) {}
    int z;
};

struct NonTrivial2 {
    NonTrivial2();
    int w;
};
NonTrivial2 :: NonTrivial2() = default;

struct NonTrivial3 {
    Trivial5 c;
    virtual void f();
};

int main(){
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    cout << is_trivial::value << endl;
    
    return 0;
}

POD的另个概念是标准布局。标准布局的类或结构体应该符合以下定义:
1)所有非静态成员有相同的访问权限。如下

struct {
public:
    int a;
private:
    int b;
};

成员a和b不同的访问权限,因此该匿名结构不是标准布局。去掉private,则是标准布局。
2)在类或者结构体集成时,满足下列情况之一:

  • 派生类中有费静态成员,且只有一个仅包含静态成员的基类。
  • 基类有非静态成员,派生类中没有非静态成员

这样的类或者结构体,也是标准布局
3)类中第一个非静态成员的类型与其基类不同。这个比较特殊,但是硬记
4)没有虚函数和虚基类
5)所有非静态数据成员均符合标准布局类型,其基类也符合标准布局

在C++11中,也可以用模板类来判断类型是否是一个标准布局的类型

template  struct std::is_standard_layout;

下面是一个例子

struct SLayout1 {};

struct SLayout2 {
private:
    int x;
    int y;
};

struct SLayout3 : SLayout1 {
    int x;
    int y;
    void f();
};

struct SLayout4 : SLayout1 {
    int x;
    SLayout1 y;
};

struct SLayout5 : SLayout1, SLayout2 {};

struct SLayout6 { static int y; };

struct SLayout7 : SLayout6 { int x; };

struct NonSLayout1 : SLayout1 {
    SLayout1 x;
    int i;
};

struct NonSLayout2 : SLayout2 {
    int z;
};

struct NonSLayout3 : NonSLayout2 {};

struct NonSLayout4 {
public:
    int x;
private:
    int y;
};

int main(){
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    cout << is_standard_layout::value << endl;
    return 0;
}

回到POD,POD需要满足平凡和标准布局两个方面。在C++11中可以通过

template  struct std::is_pod;

使用POD类型的好处包括:

  1. 字节赋值,代码中我可以安全地使用memset和memcpy对POD类型进行初始化和拷贝等操作
  2. 提供对C内存布局兼容。C++程序可以与C函数进行相互操作
  3. 保证了静态初始化的安全有效。静态初始化在很多时候能提高程序的性能,而POD累心的对象初始化往往更加简单。(静态初始化:指的是在编译时期就讲某一些对象进行了初始化;动态初始化:运行的时候才去进行初始化)

你可能感兴趣的:(深入理解C++11 3.6 POD类型)