POD 是 C++ 中一个比较重要的概念,POD 是英文 Plain Old Data 的缩写(通俗讲就是类或结构体通过二进制拷贝后还能保持其数据不变),用来描述一个类型(包括 class、union 和 struct等)的属性。其中Plain表示这个类型是个平凡的类,Old表示其与C的兼容性。C++11 中将划分为两个基本概念:平凡的(trivial)和标准布局(standard layout)。

POD的好处:

  • 字节赋值,可以放心使用memset和memcpy对POD类型进行初始化和拷贝。
  • 提供对C内存兼容。POD类型数据在C与C++间的操作总是安全的。
  • 保证静态初始化的安全有效。POD类型对象初始化往往更简单。

1、平凡性(trivial)

一个trivial class 或struct 应符合以下定义:

  • 拥有平凡的默认构造函数(trivial constructor)和析构函数(trivial destructor)。如果用户定义了构造函数或析构函数,则不能称为POD类型。
  • 拥有平凡的赋值构造函数(trivial copy constructor)和移动构造函数(trivial move constructor)。
  • 拥有平凡的复制赋值运算符(trivial assignment operator)和移动赋值运算符(trivial move operator)。
  • 不能包含虚函数和虚基类。

在c++11中可以使用default关键字来显示声明缺省版本的构造函数从而是类型恢复平凡化(第二、第三规则类似),同时c++11也提供了一个类模板来帮助我们识别一个类是否平凡的。

template <typename T>struct std::is_trival

下列中A1、A3为trivial类,A2为非trivial类

class A1 {};

class A2 {
public:
A2(){}
}; class A3 {
public:
A3() = default;
A3(int a3){}
}; int main() {
cout<<boolalpha<<is_trivial<A1>::value<<endl;
cout<<boolalpha<<is_trivial<A2>::value<<endl;
cout<<boolalpha<<is_trivial<A3>::value<<endl;
return 0;
}

2、标准布局(standard layout)

满足如下条件的类或结构体是标准布局的:

  • 所有非静态成员具有相同的访问权限,比如都是private权限,或者都是public,或者都为protected。
  • 在类或结构体的继承时,满足以下两种情况之一:
    • 派生类中有非静态成员,且只有一个仅包含静态成员的基类。、
    • 基类有非静态成员,而派生类没有非静态成员。
      class B1 { static int n; };
      class B2 : B1 { int n1; }; //派生类 B2 中有非静态成员,且只有一个仅包含静态成员的基类 B1,所以B2为标准布局。
      class B3 : B2 { static int n2; }; //基类 B2 有非静态成员,而派生类 B3 没有非静态成员,所以B3为标准布局。
  • 类中第一个非静态成员的类型与基类不同。(基于c++中优化不包括成员的基类而产生的,在c++标准中,如果基类没有成员,基类不应占空间,所以标准允许派生类的第一个成员与基类共享地址,此时基类并没有占据任何实际空间。但此时若派生类第一个成员类型仍然是基类,编译器会为基类分配一个字节空间,因为c++标准要求类型相同的对象地址不同,因此c++11强制要求POD类型的派生类第一个非静态成员类型必须不同于基类)
    class A1 {};
    class A2 {}; class B1:public A1 {
    public:
    A1 a1;
    int b1;
    }; class B2:public A1 {
    public:
    A2 a2;
    int b2;
    }; class B3:public A1 {
    public:
    int b3;
    A1 a1;
    }; int main() {
    B1 b1;b1.b1=0xb1;
    B2 b2;b2.b2=0xb2;
    B3 b3;b3.b3=0xb3; cout<<"sizeof(b1)="<<sizeof(b1)<<endl;
    cout<<"&b1 ="<<&b1<<endl;
    cout<<"&b1.a1="<<&b1.a1<<endl;
    cout<<"&b1.b1="<<&b1.b1<<endl<<endl;
    cout<<"sizeof(b2)="<<sizeof(b2)<<endl;
    cout<<"&b2 ="<<&b2<<endl;
    cout<<"&b2.a2="<<&b2.a2<<endl;
    cout<<"&b2.b2="<<&b2.b2<<endl<<endl;
    cout<<"sizeof(b3)="<<sizeof(b3)<<endl;
    cout<<"&b3 ="<<&b3<<endl;
    cout<<"&b3.b3="<<&b3.b3<<endl;
    cout<<"&b3.a1="<<&b3.a1<<endl<<endl; cout<<boolalpha<<is_standard_layout<B1>::value<<endl;
    cout<<boolalpha<<is_standard_layout<B2>::value<<endl;
    cout<<boolalpha<<is_standard_layout<B3>::value<<endl;
    return 0;
    } /* *
    * sizeof(b1)=8
    * &b1 =0x62fe48
    * &b1.a1=0x62fe49
    * &b1.b1=0x62fe4c
    *
    * sizeof(b2)=8
    * &b2 =0x62fe40
    * &b2.a2=0x62fe40
    * &b2.b2=0x62fe44
    *
    * sizeof(b3)=8
    * &b3 =0x62fe38
    * &b3.b3=0x62fe38
    * &b3.a1=0x62fe3c
    *
    * false
    * true
    * true
    * */
  • 没有虚拟函数和虚拟基类。
  • 所有非静态成员均符合标准布局类型,其基类也符合标准布局。

3、POD的使用

当一个数据类型满足“trivial”和“standard layout”,我们则认为它是POD数据库。

c++ 提供了模板来判断一个类或结构体对象是否标准布局

template <typename T> structstd::is_standard_layout; //头文件为<type_traits>
template <typename T> struct std::is_pod //判断一个类型是否是POD,头文件为<type_traits>

所有兼容C语言的数据类型都是 POD 类型(struct、union 等不能违背上述规则)。

用例:

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类型进行二进制拷贝后,数据成功进行了迁移。

C++ POD 类型的更多相关文章

  1. c++11 pod类型(了解)

    啥是POD类型? POD全称Plain Old Data.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. 平凡的定义 .有平凡的构造函数 .有平凡的拷贝构造函数 ...

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

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

  3. 关于POD和非POD类型中,list initialization和constructor initialization(未解决)

    如果你的成员是POD类型的,那么list initialization和constructor initialization没有任何区别 #include<iostream> using ...

  4. C++11 POD类型

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

  5. POD类型

    POD类型 POD全称Plain Old Data.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. C++11将POD划分为两个基本概念的合集,即:平凡的和标准 ...

  6. 3. C++ POD类型

    POD全称Plain Old Data,通常用于说明1个类型的属性.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. C++11将POD划分为2个基本概念的合集, ...

  7. 关于C++ 中POD类型的解析

    转自: http://liuqifly.spaces.live.com/blog/cns!216ae3a149106df9!221.entry (C++-98:1.8;5)给出的定义:将对象的各字节拷 ...

  8. C++ POD类型

    POD( Plain Old Data)概念: Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to m ...

  9. 聚合类型与POD类型

    Lippman在<深度探索C++对象模型>的前言中写道: I have heard a number of people over the years voice opinions sim ...

随机推荐

  1. 【LeetCode】378. Kth Smallest Element in a Sorted Matrix 解题报告(Python)

    [LeetCode]378. Kth Smallest Element in a Sorted Matrix 解题报告(Python) 标签: LeetCode 题目地址:https://leetco ...

  2. Java并发:五种线程安全类型、线程安全的实现、枚举类型

    1. Java中的线程安全 Java线程安全:狭义地认为是多线程之间共享数据的访问. Java语言中各种操作共享的数据有5种类型:不可变.绝对线程安全.相对线程安全.线程兼容.线程独立 ① 不可变 不 ...

  3. Pydantic使用

    Pydantic可以在代码运行时提供类型提示, 数据校验失败时提供友好的错误提示, 使用Python的类型注解来进行数据校验和settings管理 一般使用 from datetime import ...

  4. JUC之集合中的线程安全问题

    集合线程安全问题 JDK Version:9 首先说下集合线程安全是什么:当多个线程对同一个集合进行添加和查询的时候,出现异常错误. 复现例子: package com.JUC; import jav ...

  5. Java初学者作业——定义英雄类(Hero),英雄类中的属性包括:姓名、攻击力、防御力、生命值和魔法值;方法包括:攻击、介绍。

    返回本章节 返回作业目录 需求说明: 定义英雄类(Hero),英雄类中的属性包括:姓名.攻击力.防御力.生命值和魔法值:方法包括:攻击.介绍. 实现思路: 分析类的属性及其变量类型. 分析类的方法及其 ...

  6. Error: Cannot find module '@dcloudio/uni-cli-i18n' 解决方案

    这个错误是因为node_modules缺少了   '@dcloudio/uni-cli-i18n' 以下是错误信息  解决方案: yarn add -D @dcloudio/uni-cli-i18n ...

  7. JZOJ5966. [NOIP2018TGD2T3] 保卫王国 (动态DP做法)

    题目大意 这还不是人尽皆知? 有一棵树, 每个节点放军队的代价是\(a_i\), 一条边连接的两个点至少有一个要放军队, 还有\(q\)次询问, 每次规定其中的两个一定需要/不可放置军队, 问这样修改 ...

  8. 建造者模式(python)

    建造者模式将复杂对象的构建与其表示分离.建造者模式主要有两个参与者:建造者(builder)和指挥者(director) 来自为知笔记(Wiz)

  9. js 关于replace() 的使用心得

    1.前言 我想把一段话 let a = "抱歉,您当前的主治医生有紧急情况不得不下班,您的预约将由<br>医生:里斯<br>为您就诊,<br>诊室位置:门 ...

  10. Windows 重装系统,配置 WSL,美化终端,部署 WebDAV 服务器,并备份系统分区

    最新博客文章链接 最近发现我 Windows11 上的 WSL 打不开了,一直提示我虚拟化功能没有打开,但我看了下配置,发现虚拟化功能其实是开着的.然后试了各种方法,重装了好几次系统,我一个软件一个软 ...