class 是否需要是标准布局类型才能确定其成员的内存偏移量?

Does a class need to be a standard layout type to be sure of the memory offsets of its members?

假设我想写一个侵入式列表。我有一个侵入式列表 class 模板,它采用类型和指向成员的指针用作节点。它看起来大致是这样的:

// This needs to be a member of anything the intrusive list is going to store.
class IntrusiveListNode {
    // ...
}

// The intrusive list itself
template <class T, IntrusiveListNode T::*Member>
class IntrusiveList {
    // ...
};

// This is a type that is going to be stored in an intrusive list.
class IntegerListNode {
public:
    IntrusiveListNode node;

private:
    int value;
};

// An example of the how the list would be used.
IntrusiveList<IntegerListNode, &IntegerListNode::node> myList;

您要存储在列表中的每个东西都有一个 IntrusiveListNode。要将该 IntrusiveListNode 变回您可以使用的东西,例如 IntegerListNode,您可以调用一个函数,该函数根据节点在 class 中的偏移量对节点执行一些指针运算,然后将其转换为适当的类型。这似乎有效,但我认为不能保证。

我希望能够向我的 class 添加一个 static_assert 以在编译时验证您使用的类型是安全的,但我不确定是什么static_assert的条件是。我 认为 这只有在持有 IntrusiveListNode 的类型是标准布局时才能保证有效 class,但我不确定,因为标准布局类型的要求似乎比我其实需要。

特别是,标准布局类型要求所有成员都具有相同的访问控制。我需要的是能够确保指针算法能够工作。这意味着你不能在多态类型上使用它,因为结构的两个不同版本可能有不同的布局,但如果该类型混合了私有和 public 数据成员,这应该不是问题, 正确的?如果我只要求类型是非多态的,会安全吗?或者有更好的检查吗?还是我一直在做 is_standard_layout 检查?

我不能在这方面引用标准(而且我很确定这是未定义的行为领域),但您通常可以依赖数据成员相对于指向包含 [ 的指针的偏移量的一致性=21=],前提是这个指针的静态类型是常量(在你的例子中是 IntegerListNode*)。

您可能会发现在测量偏移量时相对于派生类型的指针会发生变化,但只要您总是先 reinterpret_cast 到 IntegerListNode 然后才 static/dynamic 转换为派生类型如果需要输入,我几乎会觉得舒服 :)

这并不是说这是个好主意。实现侵入式列表不需要这样的指针算法。如果您只是在 IntegerListNode 中定义一个 "next" and/or "previous" 指针(指向一个 IntegerListNode),您可以将它的指向成员的指针传递给 IntrusiveList,并且永远不需要创意转化 :)