参考资料

microsoft_trivial-standard-layout-and-pod-types
stackoverflow_trivial-vs-standard-layout-vs-pod
When is a type in c++11 allowed to be memcpyed?
is_pod vs is_trivial vs is_trivially_copyable vs is_standard_layout

关于layout

单词layout用于表示class、struct或union对象在内存中的分布,有些对象是连续占用内存区间的,而对于下面几种情况下对应的类对象,the compiler is free to choose a layout:

  • 拥有虚基类的类
  • 有虚函数的类
  • 有不同访问权限数据成员的类(members with different access control)

这些类对象里面的内存可能不是连续分配的,所以不能使用memcpymemmove类似的函数,也不可以serialized over a network

自C++11起,推出了三种traits,可以用来访问structs和classes的相关属性,分别是:

  • is_trivial<T>
  • is_standard_layout<T>
  • is_pod<T>(C++20开始废弃)
  • is_literal<T>(C++17废弃,C++20移除)

下面分别介绍这四种类型的区别:

Trivial Type

When a class or struct in C++ has compiler-provided or explicitly defaulted special member functions, then it is a trivial type. Trivial types have a trivial default constructor, trivial copy constructor, trivial copy assignment operator and trivial destructor.

一个类,如果它的默认构造函数、拷贝构造函数、拷贝运算符重载和析构函数都是trivial函数,那它就是Trivial类。

那么如何判断一个函数是否为trivial函数呢,trivial函数需要满足以下几点:

  • 函数是编译器自动生成的
  • 只可以是六种类型的函数:default ctor、copy ctor、dtor、copy assignment operator、move ctor和move assignment operator
  • 函数所在的类里没有虚函数或虚基类
  • 如果函数所在类继承于一个基类,该基类相关的函数也必须是trivial函数
  • 函数所在的类的类成员,也需要是trivial类

总结来说,如果一个类的上述四个函数都是编译器自动生成的,而且该类对应的基类和所有的成员都是trivial类型,且没有虚函数,则该类为trivial type。

参考代码如下:

#include<type_traits>
struct Trivial
{int i;
private:int j;// 注意,i和j的access不同,所以类Trivial是Trivial类,但不是standard layout类
};struct Trivial2
{int i;Trivial2(int a, int b) : i(a), j(b) {}Trivial2() = default;
private:int j;   // Different access control
};struct NotTrivial
{int a;NotTrivial() :a(0) {};// 自定义ctor会让编译器不再生成default ctor
};struct NotTrivial2
{int a;virtual void Func() {}
};
int main()
{cout << std::is_trivial<Trivial>() << endl;      // print 1cout << std::is_trivial<Trivial2>() << endl;    // print 1cout << std::is_trivial<NotTrivial>() << endl;  // print 0cout << std::is_trivial<NotTrivial2>() << endl; // print 0
}

trivial函数
trivial函数会影响以下方面(出自C++ Concurrency In Action(Second Edition) P361):

  1. 对于principle of three里的三个函数: 只有copy ctor、copy assignment operator和dtor都为trivial函数的类对应的对象,才可以用memcpymemmove来进行对象的复制
  2. 用于constexpr函数的Literal Types,需要有trivial copy ctor、trivial copy assignment operator和trivial dtor函数
  3. 如果一个类,其default ctor、copy assignment operator、copy ctor和dtor都为trivial函数,则该class can be used in a union with a user-defined ctor and dtor
  4. 如果一个类,定义了trivial copy assignment operator,则该类可以用于std::atomic<>从而提供a vlue of that type with atomic operations

Standard Layout

在layout部分里已经介绍过了,如果一个类是Standard Layout类,那么该类的对象在内存上的分配是连续的。

standard layout类应该具有以下特点:

  • 没有虚函数或者虚基类
  • 所有的非static的data members都是相同的访问级别
  • 所有的非static的data members都是standard layout类的对象
  • 如果有基类,基类也是standard layout
  • has no base classes of the same type as the first non-static data member.
  • 满足以下两个条件之一:
    (一)派生类没有非static成员,基类有,但又不可以同时继承于多个拥有non-static数据成员的基类
    (二)如果继承于一个基类,则该基类不可有非static的data members

举个例子:

// 虽然SL不是trivial类,但却是standard layout类
struct SL
{// All members have same access:int i;int j;SL(int a, int b) : i(a), j(b) {} // User-defined constructor OK
};

当继承的基类也有非static数据成员时,该类不是standard layout类:

struct Base
{int i;int j;
};// Derived类不是standard layout类, std::is_standard_layout<<Derived> == false!
struct Derived : public Base
{int x;int y;
};struct Base2
{void Foo() {}
};// std::is_standard_layout<<Derived2> == true
struct Derived2 : public Base2
{int x;int y;
};

POD types

When a class or struct is both trivial and standard-layout, it is a POD (Plain Old Data) type. The memory layout of POD types is therefore contiguous and each member has a higher address than the member that was declared before it, so that byte for byte copies and binary I/O can be performed on these types. Scalar types such as int are also POD types. POD types that are classes can have only POD types as non-static data members.

如果一个class或stuct,既是trivial类,也是standard layout类,那么该类是POD类。

POD类是老版的C语言对类型的形容,实际上,它可以分为两个部分,trivial和standard layout,所以新的C++版本把POD进行了进一步细分,在C++20开始,废弃了is_pod<T>对应的trait

对于POD类T,new T() is value-initialization(will value-initialize all members) ,and new T will not initialize the members (default-initialization).

举个代码的例子:

#include <type_traits>
#include <iostream>using namespace std;struct B
{protected:virtual void Foo() {}
};// A继承于一个有虚函数的基类,所以A既不是trivial也不是standard layout
struct A : B
{int a;int b;void Foo() override {} // Virtual function
};// Trivial but not standard-layout
struct C
{int a;
private:int b;   // Different access control,成员访问权限不同
};// Standard-layout but not trivial
struct D
{int a;int b;D() {} //User-defined constructor, 有自定义的default ctor
};struct POD
{int a;int b;
};int main()
{cout << boolalpha;cout << "A is trivial is " << is_trivial<A>() << endl; // falsecout << "A is standard-layout is " << is_standard_layout<A>() << endl;  // falsecout << "C is trivial is " << is_trivial<C>() << endl; // truecout << "C is standard-layout is " << is_standard_layout<C>() << endl;  // falsecout << "D is trivial is " << is_trivial<D>() << endl;  // falsecout << "D is standard-layout is " << is_standard_layout<D>() << endl; // truecout << "POD is trivial is " << is_trivial<POD>() << endl; // truecout << "POD is standard-layout is " << is_standard_layout<POD>() << endl; // truereturn 0;
}

Literal types

还有一个trait,叫is_literal<T>,literal类型的类,其layout可以在Compile Time确定,具体有如下类型:

  • void
  • scalar types,比如int, double等
  • references
  • Arrays of void, scalar types or references
  • A class that has a trivial destructor, and one or more constexpr constructors that are not move or copy constructors. Additionally, all its non-static data members and base classes must be literal types and not volatile.

四种类型的类的关系

POD、standard layout、trivial和literal type的关系应该是这样(我自己画的,不一定准确):

如何判断一个类的对象是否可以用memcpy来复制

根据前面的介绍,应该是需要该类为standard layout类,而查阅资料后发现,其实只要is_trivially_copyable<T>::value返回true,即可,即使不满足standard layout,也可以使用memcpy,比如下面的类:

struct T {int i;
private:int j;
};

也就是说,不用满足standard layout的类,也可以使用memcpy和memcopy,在C++ Concurrency In Action(Second Edition)里提到:

Objects with trivial copy constructors, trivial copy assignment operators, and trivial destructors can be copied with memcpy or memmove

至于std::is_standard_layout,则一般用于保证C++与其他语言(比如C语言)的内存分布一致。

std::is_standard_layou is useful for communicating with other languages (for creating language bindings to native C++ libraries e.g.), and that’s why a standard-layout class has the same memory layout of the equivalent C struct or union.

trivial、standard layout、POD和literal类型解析相关推荐

  1. 传值类型_what?你竟然不知道C#中的方法及参数的类型解析!那还不快来瞅瞅

    前言 哈哈,今天来给大家讲解一下关于C#中方法及参数的几种类型解析,没有看过的朋友,可以仔细的来瞧瞧了! 那么,还是话不多说,直接给大家献上今天的干货. 一.方法中参数的类型 1.in型参数 int ...

  2. Python静态类型解析工具简介和实践

    简介: Python是一门强类型的动态类型语言,开发者可以给对象动态指定类型,但类型不匹配的操作是不被允许的.动态类型帮助开发者写代码轻松愉快,然而,俗话说:动态一时爽,重构火葬场.动态类型也带来了许 ...

  3. 接收list参数_what?你竟然不知道C#中的方法及参数的类型解析!那还不快来瞅瞅...

    更多精彩,请点击上方蓝字关注我们! 前言 哈哈,今天来给大家讲解一下关于C#中方法及参数的几种类型解析,没有看过的朋友,可以仔细的来瞧瞧了! 那么,还是话不多说,直接给大家先上今天的干货了. 一.方法 ...

  4. 字符串类型日期时间转换为Date类型解析转换异常java.text.ParseException: Unparseable date: “2019-09-27T18:31:31+08:00”

    字符串类型日期时间转换为Date类型解析转换异常java.text.ParseException: Unparseable date: "2019-09-27T18:31:31+08:00& ...

  5. GPS GLONASS数据文件类型解析

    GPS & GLONASS数据文件类型解析 一.GPS数据格式 RINEX格式现如今已成为GPS测量应用中的标准数据格式,目前应用最为广泛.最普遍的是RINEX格式的第2个版本,该版本能够用于 ...

  6. Python 静态类型解析工具简介和实践

    一 背景 Python是一门强类型的动态类型语言,开发者可以给对象动态指定类型(动态),但类型不匹配的操作是不被允许的(强类型,如str和int两个变量无法相加). 动态类型帮助开发者写代码轻松愉快, ...

  7. 计算机专业英语祈使句,常见英语祈使句类型解析,分类对比轻松学

    原标题:常见英语祈使句类型解析,分类对比轻松学 祈使句通常主语为第二人称you,但一般不出现主语,多用于命令.建议或者请求的句子. 动词原形 Help! 救命啊! Go this way, pleas ...

  8. 在线加载谷歌地图—lyrs类型解析

    在线加载谷歌地图-lyrs类型解析 最近在用openlayers加载在线谷歌地图的时候总结了一下lyrs之后地图类型解析 m 标准路线图 r 某种改变的路线图(路线不明显) s 影像层(卫星图) y ...

  9. Django创建应用,app注册,Filed字段类型解析,魔术方法str使用。

    这篇博客根据上文Django创建第一个项目- ,从而在项目中跟进创建一个应用,以及app的注册, 模型models中的filed字段类型解析, 魔术方法 str 的使用. 工具: pycharm202 ...

  10. Appstore app链接mt参数app类型解析

    Appstore app链接mt参数app分类类型解析 对 mt=8 也很好奇不知道为什么添加.以下是经过各种搜找到的结果: mt 代表 meta-type,有效值如下: 1   Music 2    ...

最新文章

  1. c#中的模态对话框和非模态对话框
  2. python中的数字类型格式与运算_Python中的数字类型格式与运算
  3. sql中使用“where 1=1 and ....“ 到底影响效率吗,回答不会也永远不会
  4. QT-子线程或自定义类操作访问主界面UI控件的几种方法
  5. vue+element 封装公共js代码
  6. Leetcode--881. 救生艇
  7. linux代码、数据库备份
  8. 苹果确认部分AirPods Pro存在静电噪音等声音问题 将免费更换
  9. 六部门集中约谈8家网约车顺风车平台 要求加快合规步伐
  10. 新闻媒体是怎样使用计算机的,计算机技术在新闻上的应用
  11. 如何转置_数据转置用选择性粘贴,图片呢?
  12. Windows10 关闭自动更新
  13. Python collections 模块中的 deque(队列)
  14. 40线性映射07——线性变换的矩阵表示、线性变换与基的关系、线性变换坐标间的关系、线性变换在不同基下矩阵之间的关系、相似矩阵
  15. Java 常用工具类 - 校验银行卡号 BankCardUtils
  16. cad隐藏图层命令快捷键_CAD各种插件大全汇总,1G多绘图神器+快捷键命令大全,无套路分享...
  17. 产业链图谱:2021年中国显示器产业链图谱|产业链全景图
  18. sql脚本 windows导出 linux乱码,mysql query browser中文乱码的解决方法
  19. 深入理解prach的频域和时域数据
  20. Excel 多个条件同时重复时,自动标红

热门文章

  1. 虾皮shopee根据ID取商品详情 API 返回值说明
  2. 有关javaSE下载时,环境配置path不成功,在cmd命令中java,javac,java -version出现不是内部或外部命令的现象处理
  3. linux uwsgi 非root,只能以root身份运行uwsgi
  4. 小米电脑如何把计算机放桌面上,小米电脑怎么把此电脑放到桌面上
  5. rtsp开源视频播放器VideoLAN
  6. 科学家首次3D生物打印出血管化肿瘤,并成功使用免疫疗法治疗
  7. MySql主从复制 Master-slaver
  8. 深度学习之epoch
  9. 【多目标跟踪论文阅读笔记——JDE(Towards Real-Time Multi-Object Tracking)】
  10. 用html做一个分类目录网站,分类目录网站做外链