众所周知,虽然c++在一定程度上是c的超集,但c++和c有很大的不同,其中之一,就是c++的类和c的结构体有很大的区别。在c++中,如果一个类和c中的结构体相同,这样的类被称作pod(plain old data),可以通过std::is_pod检查一个类是否是pod类。下文会介绍pod的相关要求:
pod的组成
在c++,对于一个pod的类要满足那几条要求做了一个详细的概括,具体来说,is_pod可以拆分为is_trivial和is_standard_layout,is_trivial又可以拆分成is_trivially_copyable和is_trivially_constructible。trivial主要是对构造函数和析构函数的要求,standrad_layout主要是对子对象内存布局的要求,下面会分别介绍这三点。
构造与析构
在进一步学习pod类型前,必须要提的一点是,c++的类和c的结构体最大的区别在于:c++有构造函数和析构函数。对象创建时调用构造函数,对象销毁时调用析构函数,构造函数和析构函数一一配对。这个机制看似普通,却提供了很强的能力,著名的raii正是基于此。当然,这个机制也带来了一定麻烦,例如c++的异常处理,这可能是c++最复杂的机制之一了,而这些复杂度大部分来自于执行析构函数的栈解旋。而在c中,结构体是不存在构造函数和析构函数的,销毁一个对象不需要做任何额外的事情,只需要释放内存即可,这也就是c++的类和c的结构体最大的不同。
is_trivially_copyable
既然c++的类和c的结构体最大的区别在于有无构造和析构函数,这也正是这个要求想要表达的,如果一个c++的类没有析构函数(准确的说应该是析构函数是默认的,不会做任何事情,可以不执行它的析构函数),且至少存在一个拷贝/移动 构造/赋值函数,并且每一个拷贝/移动 构造/赋值函数都是默认的,这个类就是is_trivially_copyable。由于拷贝/移动 构造/赋值函数存在并且全都是默认的,这些函数的行为就相当于直接通过memcpy复制对象,而析构函数又不会执行,所以你可以随意的复制这些对象而不会又任何后果。
is_trivially_constructible
这个要求就是一个类是否有默认的构造函数,默认的构造函数可以不做任何事情,不需要太多阐述。
is_standard_layout
这个要求其实是对内存布局的一个要求,我们知道,c中的结构体很简单,没有各种引用,继承,虚函数等等东西。所以,对于c++中的一个类,如果要成为一个c中的结构体,也不应该有这些东西,这也正是is_standard_layout所要求的,当然,还额外给继承开了一个后门,但是和空基类优化结合起来,导致相对复杂,也有一定的坑。如果需要is_standard_layout,还是尽量不要使用继承吧。