c++ 聚合/POD/平凡/标准布局 介绍
前言
因为要整理近期学习的c++特性,特地出一篇来介绍POD
类型和c++11引进的Trivial
和Standard-layout
聚合
聚合是以下类型之一:
- 数组类型
- 类类型(通常,struct或union)具有
没有用户声明的构造函数 | (直到 C++11) |
---|---|
没有用户提供的构造函数(允许显式默认或删除的构造函数) | (C++11 起) (C++17 前) |
没有用户提供的、继承的或显式(指explicit ,c++17特意新加)的构造函数(允许显式默认或删除的构造函数) |
(C++17 起) (C++20 前) |
没有用户声明或继承的构造函数(相当于=default 不行了) |
(C++20 起) |
- 没有
virtual
、private
或protected
(C++17 起)基类 - 没有虚拟成员函数
没有默认的成员初始化器 | (C++11 起) (C++14 前) |
---|
聚合初始化。它是列表初始化 (C++11 起)或直接初始化 (C++20 起)的一种形式
POD(Plain Old Data)
POD规范着对象的类型,主要是为了兼容C,C++可以直接使用C库函数操作POD数据类型,拥有POD特征的类或结构体通过直接字节拷贝或二进制拷贝后依然能保持数据结构不变,POD类型在C和C++间的操作总是安全的。
特征:
- 标量类型(算术类型(整型/浮点型)、指针、成员指针、枚举类型)
- 类类型(class、struct、union)
- 从c++11起
- 是平凡(
trivial
)类型(后续介绍) - 是标准布局(
standard-layout
)类型(后续介绍) - 所有非静态成员都是POD类型
- 是平凡(
- 从c++11起
特性:
- 完全与C兼容,但是仍然可以有成员函数;POD类型标准到甚至可以与其他语言兼容;
- 可以用
std::memcpy
拷贝(对于非POD类型,即使满足TriviallyCopyable
,用std::memcpy
拷贝的行为也是未定义的) - 有更长的生命周期,从资源获取到资源释放,而非POD类型的是从构造函数结束到析构函数结束;
- POD类型对象的前部没有填充字节,即对象指针与第一个成员的指针是相等的
来自cppreference:PODType
平凡类型(TrivialType)
要求
来自cppreference:TrivialType
平凡可复制(TrivialCopyable)
要求
以下类型统称为平凡可复制类型:
- 标量类型
- 可简单复制的类,即满足以下要求的类:
- 至少一个拷贝构造函数、移动构造函数、复制赋值运算符或移动赋值运算符符合条件
- 每个符合条件的拷贝构造函数(如果有的话)都是平凡的
- 每个符合条件的移动构造函数(如果有)都是平凡的
- 每个符合条件的复制赋值运算符(如果有)都是平凡的
- 每个符合条件的移动赋值运算符(如果有)都是平凡的
- 有一个平凡的的未删除析构函数
- 这里有很多符合条件的要求,但大致如下
- 如果未删除函数(拷贝构造、移动构造、拷贝赋值、移动赋值 (标准c++20前)),则它是符合条件的。符合条件的函数(上述四者)的平凡性决定了该类是否是隐式生命周期类型,以及该类是否是可平凡复制的类型。
- 这里有很多平凡的概念,但大致如下
- 它不是用户提供的(意思是,它是被隐式定义或默认的)
- 所在类没有虚拟,包括虚基类和虚成员函数
- 对每个非静态类型类型(或类类型数组)成员,递归该要求
- 这里有很多符合条件的要求,但大致如下
- 平凡可复制对象 的数组
来自cppreference:TriviallyCopyable
使用is_trivially_copyable(C++11)可判断类型是否是平凡可复制的
std::is_trivially_copyable
对于某些函数的补充说明
平凡拷贝构造函数
平凡可复制对象可以通过手动复制其对象表示来复制,例如使用std::memmove。所有与 C 语言兼容的数据类型(POD 类型)都可以轻松复制。
符合条件的移动构造函数
平凡移动构造函数是执行与普通拷贝构造函数相同的操作的构造函数,也就是说,就像通过std::memmove一样制作对象表示的副本。所有与 C 语言兼容的数据类型(POD 类型)都可以轻松移动。
符合条件的拷贝赋值运算符
平凡拷贝赋值运算符生成对象表示的副本,就像通过std::memmove
一样。所有与 C 语言兼容的数据类型(POD 类型)都可以简单地拷贝分配。
符合条件的移动赋值运算符
平凡移动赋值运算符执行与平凡拷贝赋值运算符相同的操作,即生成对象表示的副本,就像std::memmove
一样。所有与C语言兼容的数据类型(POD类型)都可以简单地移动赋值。
符合条件的析构函数
平凡析构函数是不执行任何操作的析构函数。具有普通析构函数的对象不需要删除表达式,并且可以通过简单地释放它们的存储来处理。所有与 C 语言兼容的数据类型(POD 类型)都可以轻松破坏。
标准布局类型(Standard-layout Type)
标准布局规范着对对象的布局。标准布局类型对于与用其他编程语言编写的代码进行通信很有用。
当类或结构不包含某些C++语言功能(例如无法在C语言中找到虚函数),并且所有成员都具有相同的访问控制时,该类或结构为标准布局类型。可以在内存中对其进行复制,并且布局已经充分定义,可以由C程序使用。标准布局类具有用户定义的特殊成员函数。此外有以下特征
- 所有非静态数据成员具有相同的访问控制
- 没有虚函数或虚基类
- 没有引用类型的非静态数据成员
- 类类型的所有非静态成员和基类本身都是标准布局类型
- 没有与第一个非静态数据成员类型相同的基类
- 满足以下条件之一:
- 最底层派生类中没有非静态数据成员,并且具有非静态数据成员的基类不超过一个(换言之继承树中最多只能有一个类有非静态数据成员),或者
- 没有含非静态数据成员的基类
举两个例子,Base类和Derived类中都有非静态数据成员,因为当Derived继承于Base,有std::is_standard_layout<Derived>为false
,std::is_standard_layout<Base>为true
struct Base
{
int i;
int j;
};
// std::is_standard_layout<Derived> == false!
struct Derived : public Base
{
int x;
int y;
};
Derived 是标准布局,因为 Base 没有非静态数据成员:
struct Base
{
void Foo() {}
};
// std::is_standard_layout<<Derived> == true
struct Derived : public Base
{
int x;
int y;
};
标准布局兼容
涉及两个或两个以上满足标准布局的数据结构兼容问题,概括起来有点复杂,先直接抛cppreference
链接看吧(后续再细看),在标准布局内容下边
例子
类A满足POD类型要求,即可直接通过字节拷贝 拷贝其数据,在此情形下,字节拷贝效率是很快的
class A
{
public:
int a;
int b;
};
int main()
{
A a1;
a1.a = 10;
a1.b = 20;
char* p = new char[sizeof(A)];
memcpy(p, &a1, sizeof(A));
A* a2 = reinterpret_cast<A*>(p);
cout << a2->a << "\n" << a2->b << "\n";
}
总结
POD
概念在C98中被提出,在C++20
被启用,取而代之的是在C++11
引入的Trivial
和Standard-layout
类型,因本文所介绍内容在《深度探索C++对象模型》中会被重点介绍,待后续阅读完此书籍后,再对本文进行更多补充
引用博客
《深度探索C++对象模型》
c++ 聚合/POD/平凡/标准布局 介绍的更多相关文章
- WPF Step By Step 完整布局介绍
WPF Step By Step 完整布局介绍 回顾 上一篇,我们介绍了基本控件及控件的重要属性和用法,我们本篇详细介绍WPF中的几种布局容器及每种布局容器的使用场景,当 然这些都是本人在实际项目中的 ...
- html5/css3响应式布局介绍及设计流程
html5/css3响应式布局介绍 html5/css3响应式布局介绍及设计流程,利用css3的media query媒体查询功能.移动终端一般都是对css3支持比较好的高级浏览器不需要考虑响应式布局 ...
- 转:CSS3 Flexbox 布局介绍
转:CSS3 Flexbox 布局介绍 Flexbox是一个用于页面布局的全新CSS3模块功能.它可以把列表放在同一个方向(从左到右或从上到下排列),并且让这些列表能延伸到占用可用的空间.较为复杂的布 ...
- Android 基础:常用布局 介绍 & 使用(附 属性查询)
Android 基础:常用布局 介绍 & 使用(附 属性查询) 前言 在 Android开发中,绘制UI时常需各种布局 今天,我将全面介绍Android开发中最常用的五大布局 含 Andr ...
- AndroidStudio制作登录和注册功能的实现,界面的布局介绍
前言 大家好,给大家带来AndroidStudio制作登录和注册功能的实现,界面的布局介绍的概述,希望你们喜欢 每日一句: Success is connecting with the world a ...
- HTML 页面源代码布局介绍
http://www.cnblogs.com/polk6/archive/2013/05/10/3071451.html 此介绍以google首页源代码截图为例: 从上到下依次介绍: 1.<!D ...
- Android五大布局介绍&属性设置大全
前言 在进行Android开发中,常常需要用到各种布局来进行UI的绘制,今天我们就来讲下Android开发中最常用的五大布局介绍和相关属性的设置. 目录 Android五大布局介绍&属性设置. ...
- Python的标准库介绍与常用的第三方库
Python的标准库介绍与常用的第三方库 Python的标准库: datetime:为日期和时间的处理提供了简单和复杂的方法. zlib:以下模块直接支持通用的数据打包和压缩格式:zlib,gzip, ...
- Qt Quick 布局介绍
在 Qt Quick 中有两套与布局管理相关的类库,一套叫作 Item Positioner(定位器),一套叫作 Item Layout(布局). 定位器包括 Row(行定位器).Column(列定位 ...
随机推荐
- Python中的GIL锁
在Python中,可以通过多进程.多线程和多协程来实现多任务. 在多线程的实现过程中,为了避免出现资源竞争问题,可以使用互斥锁来使线程同步(按顺序)执行. 但是,其实Python的CPython(C语 ...
- 查询Oracle数据库的字符集
How do you check the Oracle database character set? SQL> select value from nls_database_parameter ...
- test_1 计算字符串最后一个单词的长度,单词以空格隔开
题目描述:计算字符串最后一个单词的长度,单词以空格隔开. 输入描述: 一行字符串,非空,长度小于5000. 输出描述: 整数N,最后一个单词的长度. #coding=utf-8 str = raw_ ...
- 基于rabbitmq延迟插件实现分布式延迟任务
承接上文基于redis,redisson的延迟队列实践,今天介绍下基于rabbitmq延迟插件rabbitmq_delayed_message_exchange实现延迟任务. 一.延迟任务的使用场景 ...
- Git 基本操作指南
Git 基本操作指南 内容概要 这个作业属于哪个课程 2022面向对象程序设计 这个作业要求在哪里 2022面向对象程序设计寒假作业1 这个作业的目标 Git & Github 作业正文 如下 ...
- 使用.NET 6开发TodoList应用(填坑1)——实现当前登录用户获取
系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在前面的文章里使用.NET 6开发TodoList应用(5)--领域实体创建,我们留了一个坑还没有填上,就是在数据库保存的时候 ...
- STC8H开发(五): SPI驱动nRF24L01无线模块
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- MyCms 自媒体 CMS 系统 v2.6,SEO 优化升级
MyCms 是一款基于Laravel开发的开源免费的自媒体博客CMS系统,助力开发者知识技能变现. MyCms 基于Apache2.0开源协议发布,免费且不限制商业使用,欢迎持续关注我们. V2.6 ...
- rpc基础讲解
什么是RPC 本地过程调用 远程过程调用带来的3个问题 RPC的调用过程 RPC的具体过程如下 总结 RPC.HTTP.Restful之间的区别 通过httpserver实现rpc 首先一点需要明确: ...
- Java安全之C3P0链利用与分析
Java安全之C3P0链利用与分析 0x00 前言 在一些比较极端情况下,C3P0链的使用还是挺频繁的. 0x01 利用方式 利用方式 在C3P0中有三种利用方式 http base JNDI HEX ...