我查看了以下相关问题,但似乎没有一个问题可以解决我的确切问题:one,two,three。
我正在编写一个集合,其中存储了元素(键值对)以及一些簿记信息:
struct Element {
Key key;
Value value;
int flags;
};
std::vector<Element> elements;
(为简单起见,假设Key
和Value
都是标准布局类型。无论如何,该集合不会与任何其他类型一起使用。)
为了支持基于迭代器的访问,我编写了覆盖operator->
和operator*
的迭代器,分别向用户返回键值对的指针和引用。但是,由于集合的性质,永远不允许用户更改返回的密钥。出于这个原因,我已经声明了KeyValuePair
结构:
struct KeyValuePair {
const Key key;
Value value;
};
我在迭代器上实现了operator->
,如下所示:
struct iterator {
size_t index;
KeyValuePair *operator->() {
return reinterpret_cast<KeyValuePair *>(&elements[index]);
}
};
我的问题是:reinterpret_cast
使用定义良好,还是调用未定义的行为?我试图解释标准的相关部分并检查有关类似问题的问题的答案,但是,我没有从中得出明确的结论,因为......:
key
和value
),这些成员仅在const
- 资格认证方面有所不同; T
和cv T
是布局兼容的,但它也没有说明相反的情况;此外,它要求它们具有相同的表示和对齐要求; reinterpret_cast
ed指针到结构,没有类似的明确保证。
- 但是,保证指向struct的指针指向其初始成员(9.2p19)。仅使用此信息,我发现无法推断出Element
和KeyValuePair
结构是否共享一个共同的初始序列,或者是否有任何其他共同点可以证明我reinterpret_cast
的合理性。
顺便说一句,如果您认为使用reinterpret_cast
用于此目的是不合适的,而且我真的面临XY问题,因此我应该做其他事情来实现我的目标,让我知道。
答案 0 :(得分:7)
我的问题是:这是使用reinterpret_cast定义良好,还是确实如此 它调用未定义的行为?
reinterpret_cast
这里是错误的做法,你只是违反了严格的别名。 reinterpret_cast
和union
在这里有所不同,但有些令人困惑,但这种情况的措辞非常明确。
你最好简单地定义一个联盟:
union elem_t {
Element e{}; KeyValuePair p;
/* special member functions defined if necessary */
};
...并将其用作矢量元素类型。请注意,在确定布局兼容性时,将忽略cv-qualification - [basic.types] / 11:
两种类型 cv1
T1
和 cv2T2
是布局兼容类型,如果T1
和T2
属于同一类型,[...]
因此,Element
和KeyValuePair
确实共享一个共同的初始序列,并且访问p
的相应成员,如果e
存在,则定义良好。< / p>
另一种方法:定义
struct KeyValuePair {
Key key;
mutable Value value;
};
struct Element : KeyValuePair {
int flags;
};
现在提供一个迭代器,它只是从向量中包装const_iterator
并向上转换要公开的引用/指针。 key
无法修改,但value
将是。