reinterpret_cast 从对象到第一个成员

reinterpret_cast from object to first member

我在看这个 answer,我想知道使用 reinterpret_cast 将对象强制转换为它的第一个成员并使用结果在 C++ 中是否安全。

假设我们有一个 class A、一个 class B 和一个 B 的实例 b:

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

class B{
public:
    A a;
};

B b;

问题 1:这样使用 b.a 安全吗:reinterpret_cast<A*>(&b)->foo()?

注意:一般情况下我们假设class及其成员都是标准布局。

我在 reinterpret_cast tells me such usage should be authorized as there is no aliasing violation, however it conflicts with many answers like this one.

上的可用参考资料讲座

问题 2:这样使用 b.a 安全吗:static_cast<A*>(static_cast<void*>(&b))->foo()?

是的,因为这里的类都是standard-layout types,可以在&b&b.a之间转换。

reinterpret_cast<A*>(p) 被定义为与 static_cast<A*>(static_cast<void*>(p)) 相同,(5.2.10p7) 所以你的两个问题是等价的。

对于标准布局 类,struct/class 的地址与其第一个非静态成员 (9.2p19) 的地址相同。 static_cast to/from void* 将保留地址 (5.2.9p13),这意味着结果将有效。

如果 类 不是标准布局,您不能依赖此行为。

正式回答:是的,有些情况下你可以这样做(见@interjay的回答)。

实际答案:请不要那样做。真的。主要是直路可用时:

b.a.foo();

换句话说,如果至少有极小的机会避免类型转换,就不要使用它们。

如果您对 C++98,2003 感兴趣:

Q1 和 Q2 是相同的结构。

您的类型是PODs。 POD在实例化过程中开头没有填充是存在保证....但在继承过程中不存在保证。所以 reinterpret_cast 是不安全的... my question about POD layout

"In real life" 比较安全,因为大部分编译器都是在继承的时候进行内存布局的,比如http://phpcompiler.org/articles/virtualinheritance.html

但请注意 A 对象基地址B 对象基地址 可能具有不同值的风险。