reinterpret_cast from object to first member
Asked Answered
S

3

6

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()?

Sulphurous answered 3/6, 2015 at 10:29 Comment(0)
L
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.

Libby answered 3/6, 2015 at 10:54 Comment(3)
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.Extracurricular
+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...Felizio
@Felizio 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.Sulphurous
Y
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.

Yorick answered 3/6, 2015 at 10:58 Comment(0)
L
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.

Lamed answered 3/6, 2015 at 11:24 Comment(4)
this is why my question is specifically about standard layout types, so that they really have the same base address.Sulphurous
"standard layout type" concept is not exist in C++2003. And also I didn't find mention interesting particularly in "standard layout types" in question)Lamed
What about: "the class and its member are both standard layout"Sulphurous
Sorry. I didn't saw it for some reasons in first time when I read question for the first time.Lamed

© 2022 - 2024 — McMap. All rights reserved.