可以使用基础或[[no_unique_address]]成员的填充来存储其他基地/成员?
[注1:非静态数据成员可以共享另一个非静态数据成员的地址或基类的地址,以及通常在对象末尾插入的任何填充都可以是重用作为其他成员的存储。 - 终点注]
(BOLD MINE)
,因为no_unique_address
的唯一规范效应正在使对象潜在的重叠,哪个基础类是自动的,基础类别应适用于同样的效果。
这似乎与 [Into.Object]/9
< < < /a>
除非一个对象是零尺寸的位字段或子对象,否则该对象的地址是其占据的第一个字节的地址。 如果一个嵌套在另一个,一个非位地址的重叠寿命的对象可能具有相同的地址,或者至少一个是零大小的子对象 ,并且它们具有不同的类型; 否则,它们具有不同的地址,占据了存储的不相交字节。
似乎只有一个对象是零大小(潜在的重叠且空的),这似乎才允许重叠。
确实,GCC,Clang和MSVC都不允许非空对象重叠:
struct A
{
int x;
short y;
};
struct B
{
short b;
};
struct C : A, B {};
struct D
{
[[no_unique_address]] A a;
[[no_unique_address]] B b;
};
// Those assertions pass, but I expected the size to be `sizeof(int) * 2` instead.
static_assert(sizeof(C) == sizeof(int) * 3);
static_assert(sizeof(D) == sizeof(int) * 3);
rel =“ nofollow noreferrer”>在 rel =“ nofollow noreferrer”> [basic.types.general]/2
琐碎的模式可复制类型:
对于任何对象(除外,除了潜在重叠的subobject ),可复制的类型
t
,...基础字节...可以复制到数组中char
...
(粗体矿)
如果只有空对象可以重叠,则不清楚为什么它禁止所有可能重叠的对象,而不仅仅是空的对象。
这是怎么回事?非空的潜在重叠对象是否真的可以重叠,并且有没有办法使编译器无需扩展?
找到添加了code> [[noreflow noreferrer'> no_unique_address]]
。情节变厚:
这是否可以重复使用尾填充?
允许使用属性的成员。
而且,该建议添加了“存储的分离”部分,并且以前不存在。也许是回归?
The note in [dcl.attr.nouniqueaddr]
says:
[Note 1: The non-static data member can share the address of another non-static data member or that of a base class, and any padding that would normally be inserted at the end of the object can be reused as storage for other members.
— end note]
(bold mine)
Since the only normative effect of no_unique_address
is making the object potentially-overlapping, which base classes automatically are, the same effects should apply to base classes.
This appears to contradict [intro.object]/9
Unless an object is a bit-field or a subobject of zero size, the address of that object is the address of the first byte it occupies.
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.
This seemingly permits overlap only if one of the objects is zero-size (is potentially-overlapping and empty).
And indeed, neither GCC, Clang, nor MSVC allow non-empty objects to overlap: run on gcc.godbolt.org
struct A
{
int x;
short y;
};
struct B
{
short b;
};
struct C : A, B {};
struct D
{
[[no_unique_address]] A a;
[[no_unique_address]] B b;
};
// Those assertions pass, but I expected the size to be `sizeof(int) * 2` instead.
static_assert(sizeof(C) == sizeof(int) * 3);
static_assert(sizeof(D) == sizeof(int) * 3);
There's also [basic.types.general]/2
that governs memcpy-ing trivially copyable types:
For any object (other than a potentially-overlapping subobject) of trivially copyable type
T
, ... the underlying bytes ... can be copied into an array ofchar
...
(bold mine)
If only empty objects can overlap, then it's unclear why it bans all potentially-overlapping objects and not only the empty ones.
What's going on here? Can non-empty potentially-overlapping objects actually overlap, and is there a way to make compilers do so without extensions?
Found the proposal that added [[no_unique_address]]
. The plot thickens:
Does this allow reuse of tail padding?
Tail padding reuse is permitted for base classes, so it's also permitted for members with the attribute.
And the "disjoint bytes of storage" part was added by this very proposal, and didn't exist before. A regression perhaps?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
潜在的重叠子对象可能重叠。如果两个潜在重叠的子对象之间的大小都零,则无法发生的情况是重叠。这就是[Intro.Object]/9所说的。
也就是说,
d :: a
可能是重叠的,但是它不能与d :: b
重叠。如果有一个假设的d :: eatper_class
也可能重叠,则d :: a
实际上可能与之重叠。“可能重叠”只是“潜在的”;任何其他潜在重叠对象是否发生任何实际重叠都取决于情况。
差异是意图。
由于
no_unique_address
的好处仅在有问题的类型为空时出现,为什么还允许在非空类型上属性?因为您的代码可能不知道如果类型为空。该类型可以由用户作为模板参数提供给您的课程(例如,给出的容器)。您不希望您的代码仅仅因为用户提供了非空类型而破坏。您想要的是利用用户提供空类型时的情况。
另外,事实是,构成“空类型”的事实实际上依赖于实现。因此,有些编译器可能会给您优化,而其他编译器则没有。
因此,必须针对不是零尺寸的POS做出的规定。由于将子对象宣布为
no_unique_address
的目的是,您会像对待它一样对待它是重叠的(即使没有发生),因此禁止在琐碎的副本中使用它们只是您出于您的意图。Potentially-overlapping subobjects can overlap. What cannot happen is overlap between two potentially-overlapping subobjects if neither of them has zero size. That's what [intro.object]/9 is saying.
That is,
D::a
is potentially overlapping, but it cannot overlap withD::b
. If there were a hypotheticalD::empty_class
that was also potentially overlapping, thenD::a
could actually overlap with it."Potentially overlapping" is only "potentially"; whether any actual overlap happens with any other potentially overlapping object depends on the circumstances.
The difference is intent.
Since the benefit of
no_unique_address
only appears if the type in question is empty, why even allow the attribute on non-empty types?Because your code may not know if a type is empty. That type could be provided to your class by the user as a template parameter (the
allocator
given to containers, for example). You wouldn't want your code to break just because the user provided a non-empty type. What you want is to take advantage of the case when the user does provide an empty type.Plus, there's the fact that what constitutes an "empty type" is actually somewhat implementation-dependent. So some compilers may give you the optimization while others do not.
As such, provisions must be made for POs that are not zero-sized. Since the intent of declaring a subobject to be
no_unique_address
is that you will treat it as if it were overlapping (even if it doesn't happen to), the prohibition on using them in trivial copies merely holds you to your stated intent.