5

I was looking at this answer and I was wondering if casting an object to its first member with reinterpret_cast and using the result could be safe in C++.

Let's assume that we have a class A, a class B and an instance b of B:

class A{
public:
    int i;
    void foo(){}
};

class B{
public:
    A a;
};

B b;

Question 1: Is it safe to use b.a like this: reinterpret_cast<A*>(&b)->foo()?

Note: In the general case we suppose that the class and its member are both standard layout.

My lecture of the available references on reinterpret_cast tells me such usage should be authorized as there is no aliasing violation, however it conflicts with many answers like this one.

Question2: Is it safe to use b.a like this: static_cast<A*>(static_cast<void*>(&b))->foo()?

Community
  • 1
  • 1
Arnaud
  • 3,765
  • 3
  • 39
  • 69

3 Answers3

7

Yes, because both classes here are standard-layout types, you can convert between &b and &b.a.

reinterpret_cast<A*>(p) is defined to be the same as static_cast<A*>(static_cast<void*>(p)), (5.2.10p7) so both your questions are equivalent.

For standard-layout classes, the address of the struct/class is the same as the address of its first non-static member (9.2p19). And static_cast to/from void* will preserve the address (5.2.9p13), meaning the result will be valid.

If the classes were not standard-layout, you could not rely on this behavior.

interjay
  • 107,303
  • 21
  • 270
  • 254
  • 2
    If writing such a crazy stuff, make sure to put static_assert on both classes being is_standard_layout, to make sure that in case of further changes the assumption isn't broken. – No-Bugs Hare Jun 03 '15 at 11:02
  • +1 for the references. But OP should really understand that's not the way to go outside the lab ! A tiny little virtual in B and the layout is gone, with the consequence of the nastiest UB... – Christophe Jun 03 '15 at 19:17
  • 1
    @Christophe You are absolutely correct, I was not asking this question with the intention to use it. And if anyone has the intention to use it, a static_assert would be most welcome. – Arnaud Jun 04 '15 at 06:48
4

Formal answer: Yes, there are situations when you can do that (see the answer of @interjay).

Practical answer: Please don't do that. Really. Mainly when the straight path is available:

b.a.foo();

In other words, don't use typecasts if there is at least a minimal chance to avoid them.

dlask
  • 8,776
  • 1
  • 26
  • 30
0

If you're interesting in C++98,2003:

Q1 and Q2 are identical constructions.

Your types are PODs. It is exist guarantee that POD has no padding at the beginning during instancing....But it is not exist garantees during inheritance. So reinterpret_cast is unsafe... my question about POD layout

"In real life" it is rather safe, because most of compilers perform memory layout during inheritance like http://phpcompiler.org/articles/virtualinheritance.html

But be aware of the risk that A object base address and B object base address can have potentionally different values.

Community
  • 1
  • 1
Konstantin Burlachenko
  • 5,233
  • 2
  • 41
  • 40