标签: standard-layout

什么是聚合和POD以及它们如何/为何特殊?

常见问题解答涉及聚合和POD,并涵盖以下材料:

  • 什么是聚合
  • 什么是POD(普通旧数据)?
  • 它们有什么关系?
  • 它们如何以及为何特别?
  • C++ 11有什么变化?

c++ aggregate standard-layout c++11 c++17

525
推荐指数
6
解决办法
13万
查看次数

C++20 是否取消了类成员按升序排列的要求?

在 C++17 中有规范文本 [class.mem]/17:

分配具有相同访问控制(第 14 条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。具有不同访问控制的非静态数据成员的分配顺序未指定。

还有 [class.mem]/24:

如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同

这里有两个例子:

struct A { int x, y, z; } a;
struct F { public: int p; private: int q; public: int r; } f;
Run Code Online (Sandbox Code Playgroud)

根据上述标准文本,C++17 保证&a.x < &a.y&a.y < &a.z、 和&f.p < &f.r (但不保证&f.p < &f.q,因为F不是标准布局,所以 class.mem/24 不适用)。


但是,在 C++20 最终工作草案 N4860 中,根据CWG 2404进行了更改。[class.mem]/17 已经变成了 Note。然而,注释在 ISO 标准中是非规范的(意味着编译器供应商可以忽略它们)。我找不到任何其他可能适用的文本。

我的问题是: C++20 是否仍然在某处指定(规范地)保证&a.y < &a.z和/或&f.p < &f.r?或者编译器现在是否有权在所有情况下重新排序类成员,标准布局类的第一个子对象除外? …

c++ class language-lawyer standard-layout c++20

45
推荐指数
1
解决办法
1603
查看次数

为什么C++ 11的POD"标准布局"定义是这样的?

我正在研究C++ 11中新的,轻松的POD定义(第9.7节)

标准布局类是一个类:

  • 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
  • 没有虚函数(10.3),也没有虚基类(10.1),
  • 对所有非静态数据成员具有相同的访问控制(第11条),
  • 没有非标准布局基类,
  • 或者在最派生类中没有非静态数据成员,并且最多只有一个具有非静态数据成员的基类,或者没有具有非静态数据成员的基类,并且
  • 没有与第一个非静态数据成员相同类型的基类.

我突出了让我感到惊讶的一些事情.

如果我们容忍具有不同访问控制的数据成员会出什么问题?

如果第一个数据成员也是基类会出什么问题?即

struct Foo {};
struct Good : Foo {int x; Foo y;};
struct Bad  : Foo {Foo y; int x;};
Run Code Online (Sandbox Code Playgroud)

我承认这是一个奇怪的结构,但为什么要Bad被禁止但不是Good

最后,如果不止一个组成类有数据成员,会出现什么问题?

c++ pod standard-layout c++11

41
推荐指数
3
解决办法
6446
查看次数

是联盟成员的析构函数

C++ 11允许在以下标准中使用标准布局类型union:Union的成员具有用户定义的构造函数

我的问题是:我是否保证在union超出范围时会调用自定义析构函数?

我的理解是我们必须在切换时手动销毁和构建:http://en.cppreference.com/w/cpp/language/union#Explanation

但是像这样的例子怎么样:

{
    union S { string str;
              vector<int> vec;
              ~S() {} } s = { "Hello, world"s };
}
Run Code Online (Sandbox Code Playgroud)

s超出范围时,我是否将内存泄漏到堆上分配的字符串,因为我没有调用string析构函数?

c++ destructor unions standard-layout c++11

21
推荐指数
1
解决办法
5661
查看次数

标准布局和尾部填充

大卫霍尔曼最近在推特上发布了以下示例(我稍微减少了):

struct FooBeforeBase {
    double d;
    bool b[4];
};

struct FooBefore : FooBeforeBase {
    float value;
};

static_assert(sizeof(FooBefore) > 16);

//----------------------------------------------------

struct FooAfterBase {
protected:
    double d;
public:  
    bool b[4];
};

struct FooAfter : FooAfterBase {
    float value;
};

static_assert(sizeof(FooAfter) == 16);
Run Code Online (Sandbox Code Playgroud)

您可以检查godbolt上的clang中的布局,并查看大小更改的原因是,FooBefore成员value放置在偏移16处(保持完全对齐8 FooBeforeBase)而在FooAfter,成员value放置在偏移12处(有效地使用FooAfterBase的尾巴填充).

我很清楚这FooBeforeBase是标准布局,但FooAfterBase不是(因为它的非静态数据成员并不都具有相同的访问控制,[class.prop]/3).但是FooBeforeBase,标准布局需要这方面的填充字节是什么呢?

gcc和clang都重用了FooAfterBase填充,最后用了sizeof(FooAfter) == 16.但是MSVC没有,结果是24.每个标准是否有必要的布局,如果没有,为什么gcc和clang做他们做的事情?


有一些混乱,所以只是为了清理:

  • FooBeforeBase 是标准布局
  • FooBefore是 …

c++ g++ language-lawyer standard-layout clang++

20
推荐指数
1
解决办法
595
查看次数

具有基本类型的单个数组成员的标准布局结构的保证内存布局

考虑以下简单结构:

struct A
{
    float data[16];
};
Run Code Online (Sandbox Code Playgroud)

我的问题是:

假设平台上float有32位IEEE754浮点数(如果很重要),那么C ++标准是否可以保证预期的内存布局struct A?如果不是,它将提供什么保证和/或执行保证的方式是什么?

预期存储器布局我的意思是该结构占用16*4=64在存储器字节,每个连续4字节占用由单个floatdata阵列。换句话说,预期的内存布局意味着以下测试通过:

static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
Run Code Online (Sandbox Code Playgroud)

offsetof这里是合法的,因为A是标准布局,请参见下文)

万一这困扰您,测试实际上会通过 gcc 9 HEAD在wandbox上通过。我从未遇到过平台和编译器的结合,它们会提供证据证明该测试可能会失败,并且我很想了解它们的存在。

为什么还要关心:

  • 类似于SSE的优化需要某些内存布局(和对齐方式,我可以在此问题中忽略它,因为可以使用标准alignas说明符来处理它)。
  • 这样的结构的序列化将简单地归结为一个不错的和可移植的write_bytes(&x, sizeof(A))
  • 一些API(例如OpenGL,特别是glUniformMatrix4fv)期望这种确切的内存布局。当然,可以仅将指针传递给data数组以传递这种类型的单个对象,但是对于其中的一系列对象(例如,用于上传矩阵类型的顶点属性),仍然需要特定的内存布局。 …

c++ memory-layout language-lawyer standard-layout

20
推荐指数
1
解决办法
713
查看次数

是POD类型完全等同于琐碎的标准布局类型吗?

在C ++ 20中,不赞成使用POD的概念,因为它是琐碎且标准的布局的无意义的合成特征。但是,C ++ 20草案中的POD定义并不完全是“琐碎的和标准布局”;实际上是:

POD类是既是普通类又是标准布局类的类,并且不具有非POD类类型的非静态数据成员(或其数组)。POD类型是标量类型,POD类,这种类型的数组或这些类型之一的cv限定版本。

换句话说,POD类型不仅是琐碎的而且是标准布局的,而且也是递归的。

该递归需求是否多余?换句话说,如果一个类型既是琐碎的又是标准布局,那么它是否也自动递归地变得琐碎又是标准布局?如果答案为“否”,那么标准布局,琐碎类型却不能成为POD的例子是什么?

c++ language-lawyer standard-layout c++20

20
推荐指数
2
解决办法
229
查看次数

标准布局c ++

我正在阅读关于C++ POD,Trivial和Standard Layout类的精彩文章 我对标准布局没有清楚了解的一个属性如下: -

 A standard layout has no base classes of the same type as the first 
    non-static data member
Run Code Online (Sandbox Code Playgroud)

因此,以下将不是标准布局,因为它具有与基类相同的第一个成员

struct NonStandardLayout3 : StandardLayout1 {
    StandardLayout1 x; // first member cannot be of the same type as base
};
Run Code Online (Sandbox Code Playgroud)

但是在性能方面和属性方面,上述结构有何不同

struct StandardLayout5 : StandardLayout1 {
    int x;
    StandardLayout1 y; // can have members of base type if they're not the first   
};
Run Code Online (Sandbox Code Playgroud)

这是对此之上的修正.

c++ pod standard-layout c++11

17
推荐指数
1
解决办法
2328
查看次数

常见的初始序列和对齐

在考虑这个问题的反例时,我提出了:

struct A
{
    alignas(2) char byte;
};
Run Code Online (Sandbox Code Playgroud)

但如果这是合法的和标准的布局,它是否与布局兼容struct B

struct B
{
    char byte;
};
Run Code Online (Sandbox Code Playgroud)

此外,如果我们有

struct A
{
    alignas(2) char x;
    alignas(4) char y;
};
// possible alignment, - is padding
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
//  x  -  -  -  y  -  -  -  x  -  -  -  y  -  -  -

struct B
{
    char x;
    char y;
}; // …
Run Code Online (Sandbox Code Playgroud)

c++ memory-alignment unions standard-layout c++11

13
推荐指数
1
解决办法
916
查看次数

is_standard_layout如何有用?

据我所知,标准布局允许三件事:

  • 空基类优化
  • 向后兼容C与某些指针转换
  • 使用offsetof

现在,包含在库中的是is_standard_layout谓词元函数,但我在通用代码中看不到它的用处,因为我上面列出的那些C特性似乎极少需要检查通用代码.我唯一能想到的是在里面使用它static_assert,但这只是为了使代码更健壮而且不是必需的.

怎么is_standard_layout有用?有没有没有它的东西是不可能的,因此需要它在标准库中?

c++ standard-layout c++11

12
推荐指数
1
解决办法
1223
查看次数