因为要整理近期学习的c++特性,特地出一篇来介绍POD
类型和c++11引进的Trivial
和Standard-layout
聚合是以下类型之一:
没有用户声明的构造函数 | (直到 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规范着对象的类型,主要是为了兼容C,C++可以直接使用C库函数操作POD数据类型,拥有POD特征的类或结构体通过直接字节拷贝或二进制拷贝后依然能保持数据结构不变,POD类型在C和C++间的操作总是安全的。
特征:
trivial
)类型(后续介绍)standard-layout
)类型(后续介绍)特性:
std::memcpy
拷贝(对于非POD类型,即使满足TriviallyCopyable
,用std::memcpy
拷贝的行为也是未定义的)来自cppreference:PODType
来自cppreference:TrivialType
以下类型统称为平凡可复制类型:
这意味着一个平凡可复制的类没有虚函数或虚基类。
来自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 类型)都可以轻松破坏。
标准布局规范着对对象的布局。标准布局类型对于与用其他编程语言编写的代码进行通信很有用。
当类或结构不包含某些C++语言功能(例如无法在C语言中找到虚函数),并且所有成员都具有相同的访问控制时,该类或结构为标准布局类型。可以在内存中对其进行复制,并且布局已经充分定义,可以由C程序使用。标准布局类具有用户定义的特殊成员函数。此外有以下特征
举两个例子,Base类和Derived类中都有非静态数据成员,因为当Derived继承于Base,有std::is_standard_layout
,std::is_standard_layout
struct Base
{
int i;
int j;
};
// std::is_standard_layout == false!
struct Derived : public Base
{
int x;
int y;
};
Derived 是标准布局,因为 Base 没有非静态数据成员:
struct Base
{
void Foo() {}
};
// std::is_standard_layout< == 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++对象模型》中会被重点介绍,待后续阅读完此书籍后,再对本文进行更多补充
聚合类型与POD类型
C++中的POD类型
《深度探索C++对象模型》
附带POD在各个语言标准的演变 变化
What are Aggregates and PODs and how/why are they special?