我刚刚开始与一个正在使用reinterpret_cast
的团队合作,显然应该使用dynamic_cast
。尽管他们使用的是reinterpret_cast
,但该代码似乎仍然可以正常工作,因此我决定不进行处理,直到最近它最终停止工作为止。
struct Base {
virtual void do_work() = 0;
};
struct D1 : public Base {
virtual void do_work();
std::vector<int> i;
};
struct D2: public D1 {
void do_work()
};
struct Holds_data {
std::vector<int> i;
};
struct Use_data : public Holds_data {
virtual void do_work();
};
struct A : public Use_data, public Base {
void do_work();
};
//case 1
// this code works
Base* working = new D2();
D2* d2_inst = reinterpret_cast<D2*>(working);
//case 2
Base* fail = new A();
A* A_inst = reinterpret_cast<A*>(fail); // fails
A* A_inst = dynamic_cast<A*>(fail); // works
在情况1中,重新解释强制转换为SEEMS可以正常工作似乎没有问题。 在第2种情况下,我注意到使用重新解释演员表时std :: vector的内部数据似乎已损坏
我的问题是为什么案例1通过?在std :: vector内是否应该存在数据损坏?
答案 0 :(得分:6)
问题是Base* working = new D2();
隐式地将D2*
强制转换为Base*
(static_cast
)。
所以,如果您有:
D2* d2 = new D2();
Base* b = d2;
您不确定std::addressof(d2) == std::addressof(b)
是否正确。但是reinterpret_cast
仅在std::addressof(d2) == std::addressof(b)
为真时才有效。这样您的代码才能正确运行,就像在注释中提到的那样,只是一个幸运的巧合。
类D2
的内存布局看起来像:
class D2:
0x0000 Attributes of Base
...
0x0010 Attirbutes of D1
...
0x0020 Attributes of D2
...
Base* b = new D2()
将保存Base
的地址(0x0000)。由于基类的属性始终存储在子类的属性之前,因此b
(0x0000)中存储的地址与new D2()
(0x0000)和{{1 }}将起作用。
但是另一方面,类reinterpret_cast
的内存布局可能看起来像:
A
在这里,编译器必须先存储class A:
0x0000 Attributes of HoldData
...
0x0010 Attributes of UserData
...
0x0020 Attributes of Base
...
0x0030 Attributes of A
...
或UserData
的数据。因此,如果Base
首先被存储(如示例中所示),UserData
还将保存Base* b = new A()
的地址(0x0020),但是由于Base
并不是第一个存储的Base
中的类,A
(0x0000)返回的地址不等于new A()
(0x0020)中保存的地址,因为b
(0x0000)被隐式静态转换为new A()
。这意味着Base*
将在此处失败。
这就是case1有效而case2不正常的原因。
最后一件事:您永远不应该相信编译器始终使用相同的内存布局。关于内存布局,有很多事情没有在C ++标准中定义。 在此处使用reinterpret_cast
会导致行为不确定!