提问人:fredoverflow 提问时间:6/28/2011 最后编辑:Jonasfredoverflow 更新时间:1/3/2021 访问量:13994
琐碎布局与标准布局 vs. POD [重复]
trivial vs. standard layout vs. POD [duplicate]
问:
通俗地说,琐碎类型、标准布局类型和 POD 之间有什么区别?
具体来说,我想确定是否与任何模板参数不同。我应该选择哪种类型的特征?new T
new T()
T
is_trivial
is_standard_layout
is_pod
(作为一个附带问题,这些类型特征中的任何一个可以在没有编译器魔法的情况下实现吗?
答:
对于 POD 类型是 value-initialization(将对所有成员进行值初始化),并且不会初始化成员(default-initialization)。有关不同初始化形式之间的差异,请参阅此问题。底线:你需要.new T()
new T
is_pod
我不认为这可以用真正外行的话来完成,至少不需要很多额外的解释。重要的一点是静态初始化与动态初始化,但向外行解释这一点本身就是几页纸......
POD 在 C++98 中被(错误)定义。实际上涉及两个独立的意图,都没有很好地表达:1)如果你在C++中编译一个C结构声明,你得到的东西应该等同于你在C中得到的东西。 2)POD只需要/使用静态(而不是动态)初始化。
C++0x/11 (几乎)完全放弃了“POD”名称,转而使用“琐碎”和“标准布局”。标准布局旨在捕获第一个意图 - 使用与 C 语言中相同的布局创建内容。
由于 vs. 处理初始化,您可能想要.new T
new 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
评论
trivial + standard layout = POD
布局是类、结构或联合对象的成员在内存中的排列方式。这可能是连续的,也可能不是。很多时候,语言指定了布局,但是如果有虚拟函数,虚拟基类等,那么编译器可以自由选择布局,这可能不是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 构造函数 构造 函数。此外,它的所有非静态数据成员和基类都必须是文本类型,而不是易失性的
评论
xyz(int x, int y) :a(x), b(y) {}
评论