从其成员子对象的地址计算对象的地址

Arn*_*aud 6 c++ offset undefined-behavior language-lawyer c++11

我遇到以下情况:

//This is Public
class B{/*usefull stuff*/};
B*f();
void g(B*b)();

//Those classes are only declared the translation unit of f and g.
class Whatever1{/*Implementation details only useful to f and g*/};
class Whatever2{/*Implementation details only useful to f and g*/};
class A{
public:
    Whatever1 w1;
    Whatever2 w2;
    B b;
};
Run Code Online (Sandbox Code Playgroud)

在函数g中,我想将参数(指向B的指针)转换为指向A的指针.

B实例始终包含在A实例中.

我最终得到了这个:

ptrdiff_t lag(){
    A a;
    return (char*)&a.b-(char*)&a;}

void g(B*b){
    A*a=(A*)((char*)b-lag());
    //Work with a
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案让我非常不舒服.

这样的偏移计算是100%正确和便携吗?

它是否以任何方式触发未定义的行为?

编辑:std :: is_standard_layout <A> ::值为1.

Oli*_*ews 2

如果 aB始终包含在 an 中A,那么在 A 中添加对 B 的父级的反向引用可能会更干净。如果由于某种原因这不切实际,那么offsetof将对其进行一些清理,但否则该方法是有效的,如果有点c-ish。

void g(B*b){
    A* a = (A*)(((char*)b)-offsetof(class A,b));
    //Work with a
}
Run Code Online (Sandbox Code Playgroud)

  • 我会让这两种方式都成为显式的“reinterpret_cast”。并在“A”的构造函数中添加一个关于标准布局的“static_assert”,并且可能让“B”由“A”私有的类型构造,因此构造“B”的唯一方法是成为‘A’。UB 可能仍然有办法潜入,但在实践中不太可能发生。 (4认同)