在不同限定的struct成员上使用reinterpret_cast是否安全?

The*_*ant 7 c++ strict-aliasing language-lawyer reinterpret-cast c++11

我查看了以下相关的问题,但似乎没有一个问题可以解决我的确切问题:,,.

我正在编写一个集合,其中存储了元素(键值对)以及一些簿记信息:

struct Element {
    Key key;
    Value value;
    int flags;
};

std::vector<Element> elements;
Run Code Online (Sandbox Code Playgroud)

(为简单起见,假定两个KeyValue是标准布局的类型.收集将不会与任何其他类型的反正使用).

为了支持基于迭代器的访问,我编写了迭代器,它们分别覆盖operator->并向operator*用户返回键值对的指针和引用.但是,由于集合的性质,永远不允许用户更改返回的密钥.出于这个原因,我已经宣布了一个KeyValuePair结构:

struct KeyValuePair {
    const Key key;
    Value value;
};
Run Code Online (Sandbox Code Playgroud)

operator->在迭代器上实现了这样的:

struct iterator {
    size_t index;

    KeyValuePair *operator->() {
        return reinterpret_cast<KeyValuePair *>(&elements[index]);
    }
};
Run Code Online (Sandbox Code Playgroud)

我的问题是:这是使用reinterpret_cast定义明确,还是调用未定义的行为?我试图解释标准的相关部分并检查有关类似问题的问题的答案,但是,我没有从中得出明确的结论,因为...:

  • 这两种结构类型共享一些初始数据成员(即,keyvalue),这些成员只有不同的const资格;
  • 标准没有明确说明T并且cv T是布局兼容的,但它也没有说明相反的情况; 此外,它要求它们具有相同的表示和对齐要求;
  • 如果第一个很多成员具有布局兼容类型,则两个标准布局类类型共享一个共同的初始序列;
  • 对于包含共享一个公共初始序列的类类型成员的联合类型,允许使用任一联合成员​​(9.2p18)检查此类初始序列的成员.- 对于reinterpret_cast共享一个公共初始序列的ed指针到结构,没有类似的明确保证. - 但是,保证指向struct的指针指向其初始成员(9.2p19).

仅使用这些信息,我发现不可能推断出这些ElementKeyValuePair结构是否共享一个共同的初始序列,或者是否有任何其他共同点可以证明我的理由reinterpret_cast.

顺便说一句,如果您认为reinterpret_cast为此目的使用是不合适的,而且我真的面临XY问题,因此我应该做其他事情来实现我的目标,让我知道.

Col*_*mbo 7

我的问题是:这是使用reinterpret_cast定义良好,还是调用未定义的行为?

reinterpret_cast这是错误的方法,你只是违反了严格的别名.这里有点令人困惑reinterpret_castunion分歧,但是这个场景的措辞非常明确.

你可能最好只是简单地定义一个联盟:

union elem_t {
   Element e{}; KeyValuePair p;
   /* special member functions defined if necessary */
};
Run Code Online (Sandbox Code Playgroud)

...并将其用作矢量元素类型.请注意,在确定布局兼容性时会忽略cv-qualification - [basic.types]/11:

有两种类型的CV1 T1CV2 T2是布局兼容的类型,如果 T1T2是同一类型,[...]

因此ElementKeyValuePair确实共享共同的初始序列,以及访问的对应的部件p,提供e是活的,是良好的定义.


另一种方法:定义

struct KeyValuePair {
    Key key;
    mutable Value value;
};

struct Element : KeyValuePair {
    int flags;
};
Run Code Online (Sandbox Code Playgroud)

现在提供一个迭代器,它简单地const_iterator从向量中包装一个并向上转换要公开的引用/指针.key不可修改,但value会是.