琐碎布局与标准布局 vs. POD [重复]

trivial vs. standard layout vs. POD [duplicate]

提问人:fredoverflow 提问时间:6/28/2011 最后编辑:Jonasfredoverflow 更新时间:1/3/2021 访问量:13994

问:

通俗地说,琐碎类型、标准布局类型和 POD 之间有什么区别?

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

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

C++ 类型特征

评论

3赞 jmishra 7/3/2012
我认为现在提及这一点有点晚了。但是对于寻找详细答案的人来说,这里是链接。检查答案 R Martinho Fernandes stackoverflow.com/questions/4178175/...

答:

8赞 Armen Tsirunyan 6/28/2011 #1

对于 POD 类型是 value-initialization(将对所有成员进行值初始化),并且不会初始化成员(default-initialization)。有关不同初始化形式之间的差异,请参阅此问题。底线:你需要.new T()new Tis_pod

82赞 Jerry Coffin 6/28/2011 #2

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

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

C++0x/11 (几乎)完全放弃了“POD”名称,转而使用“琐碎”和“标准布局”。标准布局旨在捕获第一个意图 - 使用与 C 语言中相同的布局创建内容。

由于 vs. 处理初始化,您可能想要.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赞 fredoverflow 6/28/2011
所以总是成立吗?trivial + standard layout = POD
1赞 Jerry Coffin 6/28/2011
@FredOverflow:是的,但条件是它是可传递的,所以所有(非静态)成员都必须是琐碎的+标准布局。
1赞 awdz9nld 2/17/2013
@JerryCoffin可能值得一提的是,显式提及平凡类型的连续内存布局,因为这是一个非常重要的属性
3赞 JOSEPH BENOY 9/23/2020 #3

布局是类、结构或联合对象的成员在内存中的排列方式。这可能是连续的,也可能不是。很多时候,语言指定了布局,但是如果有虚拟函数,虚拟基类等,那么编译器可以自由选择布局,这可能不是contigiuos。这导致了几个问题,我们无法适当地序列化对象或传递给用其他语言(如 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 等)、references、void 数组、标量类型或引用以及具有平凡析构函数的类,以及一个或多个不移动或复制的 constexpr 构造函数 构造 函数。此外,它的所有非静态数据成员和基类都必须是文本类型,而不是易失性的

评论

2赞 r0n9 10/22/2020
它几乎来自 learn.microsoft.com/en-us/cpp/cpp/...,粘贴URL会更容易吗?
0赞 ToddR 7/13/2022
这说明一个普通类“没有用户定义的构造函数/运算符/析构函数”,然后给出一个带有用户定义构造函数 () 的普通类的示例。这是错误还是我读错了?xyz(int x, int y) :a(x), b(y) {}