C++ 11 中的POD

POD 是英文中Plain Old Data 的缩写,意如其名。 Plain 表示了POD 是普通的类型, C++中常见的类型都是这样的属性,而不像一些存在着虚函数虚继承的类型那么特别。 Old 则体现其和C 的兼容性。 比如可以用古老的memcpy() 函数进行复制, 使用memset()进行初始化等。

使用POD 有以下几个好处:

1. 字节赋值, 可以安全地使用memset 和memcpy对POD 进行初始化和拷贝等操作。

2. 提供对C内存布局兼容,C++ 程序可以与C函数进行相互操作,因为POD 的类型的数据在C和C++间操作总是安全的

3. 保证了静态初始化的安全有效。 静态初始化在很多时候能够提升程序的性能,而POD 类型的对象初始化往往简单(比如放在目标文件的.bss 段,在初始化中直接赋0)。

在C++ 11 中,对POD 划分为两个概念的集合, 即: 平凡的(Trivial) 和标准布局的。

  通常情况下, 一个平凡的类或结构体应该符合以下定义

  1. 拥有平凡的默认构造函数(Trivial constructor)和析构函数(trivial destructor)

    平凡的默认构造函数就是说构造函数什么都不干, 通常情况下, 不定义类的构造函数,编译器会为我们生产一个平凡的默认构造函数,而一旦定义了构造函数,即使构造函数不包含参数,函数提里面没有任何代码,那么该构造函数也就不再是 ‘平凡的‘。 比如:

struct NonTrivial
{
 Nontrivial() 
    {
    }
};

   也可以使用=default关键字显式申明缺省的版本的构造函数,使其’平凡化‘。

  2. 拥有平凡 的拷贝构造函数(trivial copy constructor)和移动构造函数(trivial move constructor). 平凡的拷贝构造函数基本上等同于使用memcpy进行类型的构造。同样地,也可使用=default申明默认的拷贝构造函数。平凡的移动构造函数和平凡的拷贝构造函数类似,只不是用于移动语义。

 

  3. 拥有平凡的拷贝赋值运算符(trivial assignment operator) 和移动赋值运算符(Trivial move operator),基本上与平凡的拷贝构造函数和平凡的移动构造函数运算符类似。

  4. 不能包含虚函数和虚继承

在C++ 11 中,可以使用辅助类模版类判断一个类或结构体是不是平凡的

template <typename T> struct std::is_trivial;

类is_trivial 的成员value 可以用于判断类型T 是不是平凡的类型。下面的代码总结了这四种情况:

#include <iostream>
#include <type_traits>

using namespace std;

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

struct Trivial3{
    Trivial1 a;
    Trivial2 b;
};

struct Trivial4{
    Trivial2 a[20];
};

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

struct NonTrivial1{
    NonTrivial1() : z(42)
    {

    }
    int z;
};

struct NonTrivial2{
    NonTrivial2()
    {

    }
    int w;
    
};


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

    }
};

int main(int argc, char* argv[])
{
    cout << is_trivial<Trivial1>::value << endl; //1
    cout << is_trivial<Trivial2>::value << endl; //1
    cout << is_trivial<Trivial3>::value << endl; //1
    cout << is_trivial<Trivial4>::value << endl; //1
    cout << is_trivial<Trivial5>::value << endl; //1

    cout << is_trivial<NonTrivial1>::value << endl; //0
    cout << is_trivial<NonTrivial2>::value << endl; //0
    cout << is_trivial<NonTrivial3>::value << endl; //0

    return 0;
}

 POD 包含的另外一个概念是标准布局, 标准布局的类或结构体应该符合以下的定义:

  1. 所有非静态成员有相同的访问权限(Public, protected, private)

  2. 在类或结构体继承时,满足一下两种情况之一

    a. 派生类中有非静态成员,且只有一个仅包含静态成员的基类

    b. 基类有非静态成员,而派生类没有非静态成员

  这样的类或结构体是标准布局的,比如下面的例子:

  

struct B1 { static int a; } ;
struct D1 : B1 { int d; };

struct B2 { int a; };
struct D2 : B2 { static int d; };

struct D3 : B2, B1 { static int d; };
struct D4 : B2 { int d; };
struct D5: B2, D1 { };

   D1, D2, D3都是标准布局的, D4,D5则不属于标准布局,这实际上使得非静态成员只要同时出现在基类或者派生类中, 其即属于非标准布局,而多重继承也会导致类型布局的一些变化,所以一旦非静态成员出现在多个基类中,派生类也不属于标准布局

  3. 类中的第一个非静态成员的类型与其基类相同

  

struct A : B { B b; };

   这样的情况A 就不是一个标准布局,而如下例子:

struct A:B {int a; B b; };

 则是一个标准布局

  

  4. 没有虚函数和虚继承

  5. 所有非静态数据成员均符合标准布局类型,其基类也符合标准布局。

同样,在C++11 中,可以使用模版类is_standard_layout 来判断一个类是不是标准布局的

template <typename T> struct std::is_standard_layout

通过is_standard_layout 模版类的成员 value, 可以判断出其实不是标准布局。

#include <iostream>
#include <type_traits>
using namespace std;
struct SLayout1
{

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

struct SLayout3 : SLayout1
{
    int a;
    int b;
    void f()
    {

    }
};

struct SLayout4 : SLayout1
{
    int a;
    SLayout1 b;
};

struct SLayout5 : SLayout1, SLayout3 { };

struct SLayout6 { static int a; };

struct SLayout7 :SLayout6 { int a; };

struct NonSLayout1 : SLayout1{ SLayout1 a; int i; };
struct NonSLayout2 : SLayout2{ int c; };
struct NonSLayout3 : NonSLayout2 {};
struct NonSLayout4
{
public: 
    int a;
private:
    int b;
};

int main(int argc, char* argv[])
{
    cout << "Is Standard layout:" << endl;
    cout << is_standard_layout<SLayout1>::value << endl; //1
    cout << is_standard_layout<SLayout2>::value << endl; //1
    cout << is_standard_layout<SLayout3>::value << endl; //1
    cout << is_standard_layout<SLayout4>::value << endl; //1
    cout << is_standard_layout<SLayout5>::value << endl; //1
    cout << is_standard_layout<SLayout6>::value << endl; //1
    cout << is_standard_layout<SLayout7>::value << endl; //1

    cout << is_standard_layout<NonSLayout1>::value << endl; //0
    cout << is_standard_layout<NonSLayout2>::value << endl; //0
    cout << is_standard_layout<NonSLayout3>::value << endl; //0


	return 0;
}

  同样,要判断一个类型是不是POD, 标准库中的<type_traits> 头文件提供了如下模版类:

template<typename T> struct std::is_pod;

可以使用std::is_pod<T>::value 来判断一个类型是不是POD。

转载于:https://www.cnblogs.com/zhouminliang/p/3357073.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值