POD(Plain Old Data,普通旧数据)类型是从 C++11 开始引入的概念,Plain 代表一个对象是一个普通类型,Old 代表一个对象可以与 C 兼容。通俗地讲,一个类、结构、共用体对象或非构造类型对象能通过二进制拷贝(如 memcpy())后还能保持其数据不变正常使用的就是POD类型的对象。严格来讲,一个对象既是普通类型(Trivial Type)又是标准布局类型(Standard-layout Type)那么这个对象就是 POD 类型。

不同类型的对象意味着对象的成员在内存中的布局是不同的。在某些情况下,布局是有规范明确的定义,但如果类或结构包含某些 C++ 语言功能,如虚拟基类、 虚函数、 具有不同的访问控制的成员,则不同编译器会有不同的布局实现,具体取决于编译器对代码的优化方式,比如实现内存对齐,减少访存指令周期。例如,如果类具有虚函数,该类的所有实例都会包含一个指向虚函数表的指针,那么这个对象就不能直接通过二进制拷贝的方式传到其它语言编写的程序中使用。

C++ 给定对象类型取决于其特定的内存布局方式,一个对象是普通、标准布局还是 POD 类型,可以根据标准库函数模板来判断:

is_trivial<T>
is_standard_layout<T>
is_pod<T>

使用时需要包含头文件<type_traits>

1.普通类型

当类或结构体同时满足如下几个条件时是普通类型:
(1)没有虚函数或虚基类;
(2)由C++编译器提供默认的特殊成员函数(默认的构造函数、拷贝构造函数、移动构造函数、赋值运算符、移动赋值运算符和析构函数);
(3)数据成员同样需要满足条件(1)和(2)。

注意,普通类型可以具有不同的访问说明符。下面我们使用模版类std::is_trivial<T>::value来判断数据类型是否为普通类型。

#include <iostream>
#include <string>class A { A() {} };
class B { B(B&) {} };
class C { C(C&&) {} };
class D { D operator=(D&) {} };
class E { E operator=(E&&) {} };
class F { ~F() {} };
class G { virtual void foo() = 0; };
class H : virtual F{};
class I {};int main() {std::cout << std::is_trivial<A>::value ;     //有自定义构造函数std::cout << std::is_trivial<B>::value;   //有自定义的拷贝构造函数std::cout << std::is_trivial<C>::value;    //有自定义的移动构造运算符std::cout << std::is_trivial<D>::value;   //有自定义的赋值运算符std::cout << std::is_trivial<E>::value;     //有自定义的移动赋值运算符std::cout << std::is_trivial<F>::value;   //有自定义的析构函数std::cout << std::is_trivial<G>::value;      //有虚函数std::cout << std::is_trivial<H>::value;   //有虚基类std::cout << std::is_trivial<I>::value ;      //普通类
}

程序输出结果如下:

000000001

2.标准布局类型

当类或结构体同时满足如下几个条件时是标准布局类型:
(1)没有虚函数或虚基类;
(2)所有非静态数据成员都具有相同的访问说明符;
(3)在继承体系中最多只有一个类中有非静态数据成员;
(4)子类中的第一个非静态成员的类型与其基类不同;此规则是因为 C++ 允许优化不包含成员基类而产生的。在 C++ 标准中,如果基类没有任何数据成员,基类应不占用空间,为了体现这一点,C++ 标准允许派生类的第一个成员与基类共享同一地址空间。但是如果派生类的第一个非静态成员的类型和基类相同,由于 C++ 标准要求相同类型的对象的地址必须不同,编译器就会为基类分派一个字节的地址空间。比如下面的代码:

class B1{};
class B2{};class D1: public B1 {B1 b;int i ;
};
class D2: public B1 {B2 b ;int i ;
}

D1 和 D2 类型的对象内存布局应该是相同的,但实际上是不同的,因为 D1 中基类 B1 和对象 b 都占用了 1 个字节,D2 中基类 B1 为空,并不占用内存空间。D1 和 D2 的内容布局从左至右如下图所示:

注意,这条规定 GNU C++ 遵守,Visual C++ 并不遵守。
(5)所有非静态数据成员同样需要满足条件(1)、(2)、(3)和(4)。

考察如下程序:

#include <iostream>
using namespace std;class A { virtual void foo() = 0; };class B {private:int a;
public:int b;
};class C1 {int x1;
};class C:C1 {int x;
};class D1 {};
class D : D1 {D1 d1;
};class E : virtual C1 {};
class F { B x; };
class G :C1, D1 {};int main() {std::cout << std::is_standard_layout<A>::value ;  // 有虚函数  std::cout << std::is_standard_layout<B>::value ;  // 成员a和b具有不同的访问权限  std::cout << std::is_standard_layout<C>::value ;  // 继承树有非静态数据成员的类超过1个  std::cout << std::is_standard_layout<D>::value ;  // 第一个非静态成员是基类类型std::cout << std::is_standard_layout<E>::value ;  // 有虚基类std::cout << std::is_standard_layout<F>::value ;  // 非静态成员x不符合标准布局类型std::cout << std::is_standard_layout<G>::value ;  // return 1return 0;
}

程序运行结果:

00000001

3.POD 类型简介

一个对象既是普通类型(Trivial Type)又是标准布局类型(Standard-layout Type)那么这个对象就是POD类型。为什么我们需要 POD 类型满足这些条件呢,POD 类型在源码层级的操作上兼容于 ANSI C。POD 对象与 C 语言中的对象具有一些共同的特性,包括初始化、复制、内存布局与寻址:
(1)可以使用字节赋值,比如用 memset、memcpy 对 POD 类型进行赋值操作;
(2)对 C 内存布局兼容,POD 类型的数据可以使用 C 函数进行操作且总是安全的;
(3)保证了静态初始化的安全有效,静态初始化可以提高性能,如将 POD 类型对象放入 BSS 段默认初始化为 0。

下面看一下 POD 类型的二进制拷贝示例:

#include <iostream>
using namespace std;class A {public:int x;double y;
};int main() {if (std::is_pod<A>::value) {std::cout << "before" << std::endl;A a;a.x = 8;a.y = 10.5;std::cout << a.x << std::endl;std::cout << a.y << std::endl;size_t size = sizeof(a);char *p = new char[size];memcpy(p, &a, size);A *pA = (A*)p;std::cout << "after" << std::endl;std::cout << pA->x << std::endl;std::cout << pA->y << std::endl;delete p;}return 0;
}

程序运行结果如下:

before
8
10.5
after
8
10.5

可见,POD 类型使用字节拷贝可以正常进行赋值操作。

事实上,如果对象是普通类型,不是标准布局,例如类同时有 public 与 private 的非静态数据成员,也可以使用 memcpy 进行字节拷贝赋值。如果对象是标准布局类型,不是普通类型,例如类有复杂的 move 与 copy 构造函数,也可以使用 C 函数进行操作。


参考文献

[1] Trivial、standard-layout 和 POD 类型
[2] C++11之POD类型
[3] C++11新特性之POD类型
[4] POD (程序设计).wikipedia
[5] 深入理解C++11[M].C3.8POD类型

C++11 POD 类型相关推荐

  1. C++11 POD类型

    POD,全称plain old data,plain代表它是一个普通类型,old代表它可以与c兼容,可以使用比如memcpy()这类c中最原始函数进行操作.C++11中把POD分为了两个基本概念的集合 ...

  2. C++11新特性之POD类型

    POD(Plain Old Data)是C++中非常重要的一个概念,用来描述一个类型的属性其中Plain表示这个类型是个平凡的类型,Old表示其与C的兼容性.C++11中将POD划分为两个基本概念:平 ...

  3. C++11的POD类型

    POD类型的定义 必须是平凡的和有标准布局的. 平凡的构造函数与析构函数是默认的,不起任何作用的.如果自定义了,那么需要声明为default类型的. 使用std::is_trivial进行判别. 标准 ...

  4. C ++中的POD类型是什么?

    我有几次遇到这个术语POD型. 这是什么意思? #1楼 POD代表普通旧数据 - 即没有构造函数,析构函数和虚拟成员函数的类(无论是使用关键字struct还是关键字class ). 维基百科关于POD ...

  5. C++中的trivial和non-trivial构造/析构/拷贝/赋值函数及POD类型

    在侯捷的<STL源码剖析>里提到trivial和non-trivial及POD类型,相关知识整理如下. trivial意思是无意义,这个trivial和non-trivial是对类的四种函 ...

  6. 【C/C++ POD 类型】深度解析C++中的POD类型:从理论基础到项目实践

    深度解析C++中的POD类型:从理论基础到项目实践 1. C++中的POD类型(Plain Old Data) 1.1 POD类型的定义和特性 Trivial类型 Standard layout类型 ...

  7. C/C++编程:POD类型

    概叙 很久之前,C语言统一了江湖,几乎所有的系统底层都是用C写的,当时定义大的基本数据类型类型有 int.char.float 等整数类型.浮点类型.枚举.void.指针.数组.结构等等.然后只要碰到 ...

  8. C++ trivial和non-trivial构造函数及POD类型(转)

    原博客地址http://blog.csdn.net/a627088424/article/details/48595525 最近正纠结这个问题就转过来了,做了点补充(参考<深度探索C++对象模型 ...

  9. c++中的pod类型

    最早看到POD(plain old data)类型,是在imperfect c++里.我觉得这是一本把我带到c++世界里的一本很重要的书. 书里是这样解释POD的: 1.   所有标量类型(基本类型和 ...

最新文章

  1. Python再夺冠,上古语言COBOL大流行,IEEE Spectrum 2020年度编程语言排行榜出炉!...
  2. php 判断字符是否是数字_php判断输入是否是纯数字,英文,汉字的方法
  3. Java集合容器全面分析
  4. MyEclipse的安装和汉化过程
  5. OpenCL 2.0发布,带来更强悍的异构计算能力
  6. 图像形状特征提取c语言,OpenCV_局部图像特征的提取与匹配_源代码
  7. 【OpenCV】OpenCV实战从入门到精通图像的载入、显示与输出
  8. signature=12e3283d637b587235bcb4cbbfa1a5b3,A pathogen-inducible endogenous siRNA in plant immunity
  9. C++之安装boost库
  10. 网络配置实训(思科)
  11. java 观察者模式类图_设计模式——观察者模式
  12. 小程序根据国外经纬度显示地图
  13. 全开源即时通讯(IM)系统 高仿微信
  14. pve万兆网卡驱动_PVE+lede+DSM网卡硬盘直通+win10
  15. SQL Server HA - 数据库镜像 (Mirroring)
  16. QGIS二次开发 数据编辑功能等
  17. 每个前端都需要知道这些面向未来的CSS技术
  18. 【历史上的今天】8 月 7 日:“哈佛马克一号”正式完成;Linux 权威诞生;信息论先驱出生
  19. 网站为什么会被劫持,被劫持了怎么办。
  20. NLP之TM之Dirichlet:朴素贝叶斯NB的先验概率之Dirichlet分布的应用

热门文章

  1. 推特称攻击者利用其 API 匹配用户名和电话号码
  2. NLPIR语义智能平台支持大数据个性化学习
  3. jQuery插件开发的准备
  4. 多控制器之UIWindow
  5. AngularJS控制器和AngularJS过滤器的学习(3)
  6. 【Divided Two】cpp
  7. java基础入门之数组循环初始化
  8. Jmeter java协议配置文件导入
  9. 15款优雅的 WordPress 电子商务网站主题
  10. linux egrep和grep区别,linux中grep和fgrep有什么区别