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)
(为简单起见,假定两个Key
和Value
是标准布局的类型.收集将不会与任何其他类型的反正使用).
为了支持基于迭代器的访问,我编写了迭代器,它们分别覆盖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
定义明确,还是调用未定义的行为?我试图解释标准的相关部分并检查有关类似问题的问题的答案,但是,我没有从中得出明确的结论,因为...:
key
和value
),这些成员只有不同的const
资格;T
并且cv T
是布局兼容的,但它也没有说明相反的情况; 此外,它要求它们具有相同的表示和对齐要求;reinterpret_cast
共享一个公共初始序列的ed指针到结构,没有类似的明确保证. - 但是,保证指向struct的指针指向其初始成员(9.2p19).仅使用这些信息,我发现不可能推断出这些Element
和KeyValuePair
结构是否共享一个共同的初始序列,或者是否有任何其他共同点可以证明我的理由reinterpret_cast
.
顺便说一句,如果您认为reinterpret_cast
为此目的使用是不合适的,而且我真的面临XY问题,因此我应该做其他事情来实现我的目标,让我知道.
我的问题是:这是使用reinterpret_cast定义良好,还是调用未定义的行为?
reinterpret_cast
这是错误的方法,你只是违反了严格的别名.这里有点令人困惑reinterpret_cast
和union
分歧,但是这个场景的措辞非常明确.
你可能最好只是简单地定义一个联盟:
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
T1
和CV2T2
是布局兼容的类型,如果T1
和T2
是同一类型,[...]
因此Element
和KeyValuePair
确实共享共同的初始序列,以及访问的对应的部件p
,提供e
是活的,是良好的定义.
另一种方法:定义
struct KeyValuePair {
Key key;
mutable Value value;
};
struct Element : KeyValuePair {
int flags;
};
Run Code Online (Sandbox Code Playgroud)
现在提供一个迭代器,它简单地const_iterator
从向量中包装一个并向上转换要公开的引用/指针.key
不可修改,但value
会是.