1

If two classes A and B are of standard layout and B is defined as

class B {
  // any methods
  A a;
}

then it is safe to do

A a;
B* b = reinterpret_cast<B*>(&a);

If A now is replaced by std::pair<T1, T2>, will this work for every possible T1, T2, too? As far as I know, std::pair<T1, T2> is of standard layout if both T1 and T2 are of standard layout, but if they aren't, would this affect the possibility to safely reinterpret_cast in this case?

csk
  • 313
  • 2
  • 11
  • I think you are okay in this limited (`std::is_standard_layout`) situation. Amiga OS used to do that sort of thing a lot. – Eljay Apr 14 '18 at 20:12
  • There's some ambiguity here. There's nothing in the clause that defines a `std::pair` that explicitly states if `T1` and `T2` are a standard-layout-class then the resulting `std::pair` is a standard-layout class. It just describes the resulting class loosely, as a "pair" of `T1` and `T2`. I can see the argument that this loose implementation, combined with a more explicit definition of what a standard-layout class is, must mean that the resulting `std::pair` becomes a standard-layout pair. I would say that this is implementation-defined. Good question. – Sam Varshavchik Apr 14 '18 at 20:33
  • @SamVarshavchik: well, I've got this assumption from this [SO question](https://stackoverflow.com/questions/6687107/difference-between-stdpair-and-stdtuple-with-only-two-members): `"Every std::pair is standard-layout if both T and Y are standard-layout."` – csk Apr 14 '18 at 20:46

1 Answers1

1

If A now is replaced by std::pair<T1, T2>, will this work for every possible T1, T2 too?

No, it wouldn't even work in this specific case.

would this affect the possibility to safely reinterpret_cast in this case?

Not at all. The cast is invalid in both cases.

You are violating the informal strict aliasing rule. More specifically, according to the standard, you are casting a pointer to an object (here &a, where a is the object) to B*. Any attempt to dereference that B* will be UB because you do not have an object B.

You might think that you have an object, but actually, according to the standard, you don't. From [intro.object]p1:

An object is created by a definition ([basic.def]), by a new-expression, when implicitly changing the active member of a union ([class.union]), or when a temporary object is created ([conv.rval], [class.temporary]).

None of those cases apply, so you have UB if you try to use the "object" b which isn't one.

Now, you should consult with your implementation, because a lot of implementations provide a basic guarantee for constructs like yours IIRC.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162