Is this use of reinterpret_cast for various qualified structural elements safe?

I looked at the following questions, and none of them seem to relate to my exact problem: one , two , three .

I am writing a collection that stores items (key-value pairs) along with some accounting information:

struct Element { Key key; Value value; int flags; }; std::vector<Element> elements; 

(For simplicity, suppose both Key and Value are standard layout types. In any case, the collection will not be used with any other types.)

To support iterator-based access, I wrote iterators that override operator-> and operator* to return a pointer and a link to a pair of key values, respectively. However, due to the nature of the collection, the user is never allowed to modify the returned key. For this reason, I declared a KeyValuePair structure:

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

And I implemented operator-> in an iterator as follows:

 struct iterator { size_t index; KeyValuePair *operator->() { return reinterpret_cast<KeyValuePair *>(&elements[index]); } }; 

My question is: is this using reinterpret_cast good, or does it cause undefined behavior? I tried to interpret the relevant parts of the standard and examined the answers to questions about similar problems, but I could not draw a final conclusion from them, because ...:

  • two types of structures have several source data elements (namely Key and Value ) that differ only in const qualification;
  • the standard does not explicitly say that T and cv T compatible with layouts, but it also does not indicate otherwise; in addition, it provides that they must have the same requirements for submission and approval;
  • Two types of standard layout classes share a common initial sequence, if in the first case many members have types compatible with layouts;
  • for union types containing members of a class type that have a common initial sequence, it is allowed to examine members of that initial sequence using any of the members of the union (9.2p18). - There is no similar explicit guarantee made about reinterpret_cast ed pointer-structures having a common initial sequence. - however, it is guaranteed that the pointer-to-structure points to its initial term (9.2p19).

Using only this information, it was impossible for me to determine if the Element and KeyValuePair structures KeyValuePair common common starting sequence or something else that would justify my reinterpret_cast .

As an aside, if you think that using reinterpret_cast for this purpose is inappropriate, and I am really facing the XY problem, and therefore I just have to do something else to achieve my goal, let me know.

+7
c ++ language-lawyer strict-aliasing c ++ 11 reinterpret-cast
source share
1 answer

My question is: is reinterpret_cast usage clearly defined or is it causing undefined behavior?

reinterpret_cast is the wrong approach here, you are just breaking a strict alias. It is somewhat puzzling that reinterpret_cast and union diverge here, but the wording is very clear in this scenario.

It may be easier for you to simply define the union this way:

 union elem_t { Element e{}; KeyValuePair p; /* special member functions defined if necessary */ }; 

... and using this as your type of vector element. Please note that cv-qualification is ignored when defining layout layout - [basic.types] / 11:

Two types cv1 T1 and cv2 T2 are layout compatible types if T1 and T2 are the same type, [...]

Therefore, Element and KeyValuePair do have a common starting sequence, and access to the corresponding members of p , provided that e is alive, is well defined.


Another approach: Define

 struct KeyValuePair { Key key; mutable Value value; }; struct Element : KeyValuePair { int flags; }; 

Now provide an iterator that simply const_iterator from the vector and picks up the links / pointers that should be exposed. key will not change, but value will.

+7
source share

All Articles