gpt4 book ai didi

c++ - 什么可以防止类中相邻成员重叠?

转载 作者:行者123 更新时间:2023-12-01 11:56:03 25 4
gpt4 key购买 nike

考虑以下三个 struct s:

class blub {
int i;
char c;

blub(const blub&) {}
};

class blob {
char s;

blob(const blob&) {}
};

struct bla {
blub b0;
blob b1;
};

在典型平台上 int为4个字节,大小、对齐方式和总padding1如下:
  struct   size   alignment   padding  
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6

blub的存储之间没有重叠和 blob成员,即使大小为 1 blob原则上可以“适合”在 blub 的填充中.

C++20 引入了 no_unique_address属性,它允许相邻的空成员共享相同的地址。它还明确允许使用一个成员的填充来存储另一个成员的上述场景。来自 cppreference (强调我的):

Indicates that this data member need not have an address distinct from all other non-static data members of its class. This means that if the member has an empty type (e.g. stateless Allocator), the compiler may optimise it to occupy no space, just like if it were an empty base. If the member is not empty, any tail padding in it may be also reused to store other data members.



事实上,如果我们在 blub b0 上使用这个属性,大小 bla下降到 8 ,所以 blob确实存储在 blub as seen on godbolt .

最后,我们来回答我的问题:

标准(C++11 到 C++20)中的哪些文本可以在没有 no_unique_address 的情况下防止这种重叠,对于不能简单复制的对象?

我需要从上面排除平凡可复制(TC)对象,因为对于 TC 对象,允许 std::memcpy从一个对象到另一个对象,包括成员子对象,如果存储重叠,这将中断(因为相邻成员的全部或部分存储将被覆盖)2。

1 我们将填充简单地计算为结构大小与其所有组成成员的大小之间的差异,递归。

2 这就是为什么我定义了复制构造函数:使 blubblob不可复制。

最佳答案

该标准在谈论内存模型时非常安静,并且对它使用的某些术语不是很明确。但我想我找到了一个有效的论证(可能有点弱)
首先,让我们找出什至是对象的一部分。 [basic.types]/4 :

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object of type T is the set of bits that participate in representing a value of type T. Bits in the object representation that are not part of the value representation are padding bits.


所以 b0的对象表示由 sizeof(blub) 组成 unsigned char对象,所以 8 个字节。填充位是对象的一部分。
如果不是嵌套在另一个对象中,则任何对象都不能占用另一个对象的空间 [basic.life]/1.5 :

The lifetime of an object o of type T ends when:

[...]

(1.5) the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).


所以 b0的生命周期将结束,当它占用的存储空间被另一个对象重用时,即 b1 .我还没有检查过,但我认为标准要求一个活着的对象的子对象也应该是活着的(我无法想象这应该如何不同地工作)。
所以存储 b0 b1 不能使用占用.我在标准中没有找到“占用”的定义,但我认为合理的解释是“对象表示的一部分”。在描述对象表示的引文中,使用了“占用”一词1。在这里,这将是 8 个字节,所以 bla需要至少一个 b1 .
特别是对于子对象(以及其他非静态数据成员)还有规定 [intro.object]/9 (但这是用 C++20 添加的,谢谢@BeeOnRope)

Two objects with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a subobject of zero size and they are of different types; otherwise, they have distinct addresses and occupy disjoint bytes of storage.


(强调我的)在这里,我们再次遇到“占用”未定义的问题,我再次争辩说在对象表示中采用字节。请注意,此 [basic.memobj]/footnote 29 有一个脚注

Under the “as-if” rule an implementation is allowed to store two objects at the same machine address or not store an object at all if the program cannot observe the difference ([intro.execution]).


如果可以证明没有可观察到的副作用,这可能允许编译器打破这一点。我认为这对于像对象布局这样的基本事物来说非常复杂。也许这就是为什么只有当用户通过添加 [no_unique_address] 来提供没有理由具有不相交对象的信息时才进行此优化的原因。属性。
tl; dr:填充可能是对象的一部分,成员必须不相交。

1 我忍不住添加一个引用,占用可能意味着占用: Webster’s Revised Unabridged Dictionary, G. & C. Merriam, 1913 (强调我的)
  1. To hold, or fill, the dimensions of; to take up the room or space of; to cover or fill; as, the camp occupies five acres of ground. Sir J. Herschel.

如果没有字典爬行,什么样的标准爬行是完整的?

关于c++ - 什么可以防止类中相邻成员重叠?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59867666/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com