问题标签 [standard-layout]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - is_standard_layout 有什么用?
据我了解,标准布局允许三件事:
- 空基类优化
- 通过某些指针转换向后兼容 C
- 偏移量的使用
现在,库中包含is_standard_layout
谓词元函数,但我看不出它在泛型代码中有多少用处,因为我上面列出的那些 C 功能似乎极少需要检查泛型代码。我唯一能想到的就是在里面使用它static_assert
,但这只是为了让代码更健壮,并不是必需的。
有is_standard_layout
什么用?没有它,是否有任何事情是不可能的,因此在标准库中需要它?
c++ - 共同的初始序列和比对
在考虑这个问题的反例时,我想出了:
但是,如果这是合法且标准的布局,那么它的布局是否与 this 兼容struct B
?
此外,如果我们有
A
和有一个共同的初始序列B
吗?如果是这样,它是否包括A::y
& B::y
?即,我们可以编写以下不调用 UB 的代码吗?
(也欢迎 C++1y/“固定 C++11”的答案)
有关对齐,请参见 [basic.align],对于对齐说明符,请参见 [dcl.align]。
[basic.types]/11 表示基本类型“如果两个类型
T1
和T2
是相同类型,那么T1
和T2
是布局兼容类型。” (一个潜在的问题是是否A::byte
并且B::byte
具有布局兼容的类型)[class.mem]/16 “如果两个标准布局结构类型具有相同数量的非静态数据成员并且相应的非静态数据成员(按声明顺序)具有布局兼容类型,则它们是布局兼容的。”
[class.mem]/18 “如果对应的成员具有布局兼容的类型,并且两个成员都不是位域或两者都是具有相同宽度的位域,则两个标准布局结构共享一个共同的初始序列。或更多初始成员。”
[class.mem]/18 “如果一个标准布局联合包含两个或多个共享一个共同初始序列的标准布局结构,并且如果标准布局联合对象当前包含这些标准布局结构之一,则允许检查其中任何一个的共同初始部分。”
当然,在语言律师的层面上,另一个问题是“允许”对公共初始序列的检查意味着什么。我猜其他一些段落可能会导致上述u.b.x
未定义的行为(从未初始化的对象中读取)。
c++ - 我可以在布局兼容的标准布局类型之间合法地 reinterpret_cast 吗?
我正在写一个类,假设答案是枚举类型布局与其底层类型兼容吗?是“是”,是布局兼容的,struct kevent
但使用enum class
es 来表示filter
,flags
等,以及相关字段的适当基础类型。它也是标准布局(字段都是private
标准布局,没有virtual
成员,没有基类)。从我对 的阅读中n3690
,我可以确定我的班级和struct kevent
具有相同的价值表示,但我看不到标准中的任何内容,因此我可以reinterpret_cast
尽管这似乎是对“价值表示”的合理解释。这在技术上是标准允许的吗?如果不是,那么知道类型的值表示会给您带来什么?
编辑 2014/02/24 东部标准时间 16:45:作为对评论的回应,我应该澄清我希望reinterpret_cast
第一类引用第二类,因为当然你不能直接reinterpret_cast
将非指针类型指向另一个非- 指针类型。
c++ - C++ - 标准布局
根据当前的 C++ 标准草案,一个标准布局类
要么在派生最多的类中没有非静态数据成员,并且最多有一个具有非静态数据成员的基类,要么没有具有非静态数据成员的基类
我还没有看到任何在这个限制下会更有效的实现。它为什么存在(除了让事情变得更困难)?
c++ - reinterpret_cast 与 static_cast 在标准布局类型中写入字节?
我需要写入某些整数类型的单个字节。我应该使用reinterpret_cast
,还是应该使用static_cast
via void*
?
(一个)
或 (b)
根据std::aligned_storage的 static_cast 和 reinterpret_cast 的答案,两者都应该是等价的——
-- 如果 T1 和 T2 都是标准布局类型,并且 T2 的对齐要求不比 T1 严格
我倾向于reinterpret_cast
因为这本质上就是我正在做的事情,不是吗?
还有其他需要考虑的事情吗,特别是我们目前正在编译的版本 Visual-C++ 和 VC8?(仅限 x86 自动取款机。)
c++ - 为什么具有不同访问控制的成员的工会不是标准布局?
§9.0
7. S 类是标准布局类,如果它:
(7.3) 对所有非静态数据成员具有相同的访问控制(第 11 条),
8 标准布局结构是使用 class-key struct 或 class-key class 定义的标准布局类。标准布局联合是使用类键联合定义的标准布局类。
AFAICT,§9.0.7.3 的存在是因为 §9.2.13
分配具有相同访问控制(第 11 条)的(非联合)类的 13 个非静态数据成员,以便后面的成员在类对象中具有更高的地址。未指定具有不同访问控制的非静态数据成员的分配顺序(第 11 条)。实现对齐要求可能会导致两个相邻的成员不会被立即分配;管理虚拟功能(10.3)和虚拟基类(10.1)的空间需求也是如此。
但是,这似乎不适用于联合,因为联合的所有(非静态数据)成员都具有相同的地址。这是标准的缺陷吗?还是有一些令人信服的理由为什么我没有看到?
c++ - 一个类是否需要是标准布局类型才能确定其成员的内存偏移量?
假设我想写一个侵入性列表。我有一个侵入式列表类模板,它采用类型和指向成员的指针以用作节点。它看起来大致是这样的:
您要存储在列表中的每件事都有一个 IntrusiveListNode 。要将 IntrusiveListNode 变回您可以使用的东西,例如 IntegerListNode,您需要调用一个函数,该函数根据节点在类中的偏移量对节点进行一些指针运算,然后将其转换为适当的类型。这似乎有效,但我认为不能保证。
我希望能够在我的类中添加一个 static_assert,以在编译时验证您使用的类型是安全的,但我不确定 static_assert 的条件是什么。我认为这只有在持有 IntrusiveListNode 的类型是标准布局类时才能保证有效,但我不确定,因为标准布局类型的要求似乎比我实际需要的更严格。
特别是,标准布局类型要求所有成员具有相同的访问控制。我需要的是能够确保指针算术能够正常工作。这意味着您不能在多态类型上使用它,因为结构的两个不同版本可能会以不同方式布局,但如果该类型混合了私有和公共数据成员,这应该不是问题,对吧?如果我只要求类型是非多态的,那会安全吗?还是有更好的检查方法?还是我卡在做is_standard_layout
检查?
c++11 - ABI 兼容的 shared_ptr 实现
我正在开发一个 COM 风格的编译器交叉兼容插件框架,它依赖于兼容的虚拟表实现来实现 ABI 兼容性。我定义了只包含纯虚成员函数和重写的删除操作符的接口,以将破坏引导到实现的地方。这适用于外部“C”工厂函数实例化接口的插件实现并返回接口类型指针。
但是,我想知道智能指针是否不是管理插件对象生命周期的更现代的方式。我想我实际上已经设法创建了一个标准布局 shared_ptr/weak_ptr ,它使用与插件接口相同的方式定义和实现的引用计数对象。它看起来像这样:
三个问题:
在智能指针之前,工厂函数如下所示:
现在,它看起来像这样:
VS2013 给我警告 C4190:'factory' 指定了 C 链接,但返回与 C 不兼容的 UDT 'shared_ptr'。根据 MSDN,只要调用者和被调用者都是 C++,就可以了。
从“C”链接函数返回标准布局对象是否还有其他潜在问题?
调用约定。我应该为所有纯虚拟接口函数和工厂函数指定 __stdcall 吗?
我正在使用
<atomic>
参考计数。我正在编写与平台无关的代码,但尚未尝试为 ARM 编译。根据http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s02s01.html armcc 没有实现 std::atomic。那里有更好的编译器/ stl吗?
c++ - 是否有可能使`=`更喜欢转换分配而不是(删除)复制分配?
我发现一些线程严重暗示这无法完成,但没有一个线程使用完全相同的运算符和条件组合,所以我想更具体地问一下。希望这意味着它对某人来说是一个快速而简单的答案......一种或另一种方式!
考虑一个示例代理类,用于管理更大存储块中的值 - 就像在这个过于简单但具有代表性的示例中一样:
我希望所有分配都通过用户定义operator
的 s 工作。在这种情况下,用户应该只能传入或传出“暴露”类型std::uint16_t
。我可能正在使用各种代理类类型,并希望这适用于所有这些类型。理想情况下,对于任何类型的组合,我只需键入someProxy = anotherProxy
并让编译器完成剩下的工作。
但是,当赋值的左侧和右侧具有相同或与继承相关的类型时,默认的复制赋值运算符 - 当然 - 与此目标冲突。它复制整个storage
,从而破坏了另一半uint32_t
- 而不是根据需要仅复制“暴露”值。没错!对于大多数情况。但我想要一种“通过转换分配”的方法,即使 LHS 和 RHS 类型相同。为了避免这种情况,我可以:
- 重新定义复制赋值运算符以使用用户定义的 s 执行“代理”复制
operator
- 这是我一直在做的,但它似乎有点 hacky ,并且像任何用户定义的构造函数/赋值运算符一样,打破了微不足道的可复制状态的struct
- 我需要保留。无论如何它仍然存在,但我想要定义memcpy()
的行为。g++
- 或
= delete
复制赋值运算符(我们现在可以对 TC 类型执行此操作)。但是分配仍然尝试使用它并引发编译错误 - 因为delete
意味着“如果我是选择的重载则中止错误”,而不是“将我排除在重载决议之外”。为了解决这个问题,我必须明确告诉编译器使用转换运算符并从其结果中赋值:
似乎没有办法告诉编译器“忽略您首选的重载产生的任何错误并选择下一个最好的错误”。在那儿?更一般地说,在这种情况下,是否有任何方法/黑客/可怕的组合来强制编译器自动使用/首选某些operator
s?
换句话说,理想情况下,在
那b = a;
真的会这样做:
无需我手动输入,使用 astatic_cast
或实现命名的 get/set 方法。理想情况下,我希望对任何此类代理的读/写看起来与对书面代码中基本类型的读/写完全相同,所有这些都使用=
.
我强烈怀疑这是不可能的......但确认会很好!
c++ - C++14 标准布局类型可以对字段使用“alignas”吗?
我想使用模板来简化具有非平凡类型的联合的构造。以下似乎在实践中“有效”,但在技术上不符合规范:
问题是(根据 N4141)只有当两个结构都是标准布局类型时,您才能访问联合中两个结构的公共初始序列(即destructor_
字段)——至少根据 9.5 中的非规范注释.1。根据 9.0.7,标准布局类型不能有任何具有非标准布局的非静态数据成员。因此,如果 A 或 B 不是标准布局,则destructor_
在错误的联合中访问是非法的。
一个漏洞似乎是union_entry
通过转入value_
. alignas(T) char[sizeof(T)]
9.0.7 中似乎没有排除使用alignas
. 因此,我的问题 是:以下是任何类型的标准布局类型T
吗? 因此可以value_
强制转换T&
为模拟前面的示例,同时仍然允许destructor_
在非活动中使用union_entry
?
在 clang-3.8.1 和 g++-6.2.1 中,std::is_standard_layout
建议union_entry<T>
是标准布局,即使T
不是。这是我想如何使用此技术的完整工作示例: