平凡与标准布局与POD

时间:2011-06-27 17:25:01

标签: c++ constructor initialization pod typetraits

用外行人的话来说,琐碎的类型,标准版面类型和POD之间有什么区别?

具体来说,我想确定new T对于任何模板参数new T()是否与T不同。我应该选择哪种类型特征is_trivialis_standard_layoutis_pod

(作为一个附带问题,可以在没有编译魔术的情况下实现这些类型特征中的任何一个吗?)

3 个答案:

答案 0 :(得分:54)

我不认为这可以用真正的外行人的术语来完成,至少没有很多的额外解释。一个重要的点是静态与动态初始化,但向外行解释这本身就是几页......

在C ++ 98中定义了(错误)POD。实际上有两个单独的意图,都没有表达得很好:1)如果你在C ++中编译一个C结构声明,你得到的应该与你在C中的相同.2)POD只需要/使用静态(不是动态的)初始化。

C ++ 0x / 11完全删除了“POD”(几乎)的名称,支持“琐碎”和“标准布局”。标准布局旨在捕获第一个意图 - 使用与C中相同的布局创建内容.Trivial旨在捕获对静态初始化的支持。

由于new Tnew T()处理初始化,您可能想要is_trivial

我不确定是否需要编译器魔法。我的直接反应可能是肯定的,但是知道人们对TMP所做的一些事情,我很难确定有人也做不到这个......

编辑:例如,也许最好只引用N3290的例子:

struct N { // neither trivial nor standard-layout
   int i;
   int j;
    virtual ~N();
};

struct T { // trivial but not standard-layout
    int i;
private:
    int j;
};

struct SL { // standard-layout but not trivial
    int i;
    int j;
    ~SL();
};

struct POD { // both trivial and standard-layout
    int i;
    int j;
};

正如您无疑可以猜到的那样,POD也是一个POD结构。

答案 1 :(得分:7)

对于POD类型new T()是值初始化(将对所有成员进行值初始化),new T不会初始化成员(默认初始化)。对于不同形式的初始化see this question之间的差异。底线:您需要is_pod

答案 2 :(得分:0)

布局 是类,结构或联合的对象的成员在内存中的排列方式。这可能是不连续的。语言经常指定布局,但是如果存在诸如虚函数,虚拟基类等内容,那么编译器可以自由选择布局,而这可能不是连续的。这导致了一些问题,我们无法适当地序列化对象或将其传递给使用其他语言(如C)或函数(如memcopy)编写的程序,因为我们无法可靠地复制不在相邻位置的数据。

为了使编译器和c ++程序能够支持上述操作,c ++为简单的结构和类引入了3类。

优惠

如果类或结构遵循以下规则,则它是微不足道的:

  • 没有虚拟功能或虚拟基类
  • 没有用户定义的构造函数/运算符/析构函数
  • 基类应该很简单
  • 所有班级成员都应该平凡

如果一个类是琐碎的,则其布局是连续的,但可能会有相应的填充,并且编译器可以自由选择布局中成员的顺序。因此,即使我们可以复制对象,如果将对象复制到C程序中也不可靠。我们可以在同一个类中拥有不同的访问说明符,并且如果使用参数化构造函数,则显然必须指定默认构造函数。但是,如果您想让该类琐碎,那么应该显式地将构造函数设为默认值。构造函数应该是公共的。

标准版式

  • 没有虚拟功能和虚拟基类
  • 所有非静态成员应具有相同的访问说明
  • 所有非静态成员均应采用标准布局
  • 所有基类均应采用标准布局
  • 基类的所有成员都应该是静态的
  • 基类的类型和该类的第一个非静态成员的类型不应相同

标准布局定义明确,可以可靠地复制并适当地传递给C程序。 此外,标准布局功能还可以具有用户定义的特殊成员功能,例如构造函数和析构函数。

POD(普通旧数据)

如果一个类或结构既是普通布局又是标准布局,则称其为POD。每个成员按照声明对象时指定的顺序存储。 POD类应具有POD非静态数据成员。可以将POD类可靠地复制或传递给C程序。

C ++程序的类很小,是标准布局,因此是POD。

#include<iostream>
#include<type_traits>
class xyz
{
public:
    int a;
    int b;
    xyz() = default;
    xyz(int x, int y) :a(x), b(y) {}
};
int main() {
    std::cout << std::is_trivial<xyz>() << std::endl;//true
    std::cout << std::is_standard_layout<xyz>() << std::endl;//true
    std::cout << std::is_pod<xyz>() << std::endl;//true
}

文字类型

对于文字类型,可以在编译时确定布局。文字类型的示例为void,标量类型(如int,float等),引用,void的数组,标量类型或引用以及具有琐碎的析构函数,以及一个或多个不移动或复制的constexpr构造函数 构造函数。此外,其所有非静态数据成员和基类都必须是文字类型,并且必须是可变的