【发布时间】:2016-12-26 16:12:19
【问题描述】:
以下代码安全吗:
#include <iostream>
#include <cstdint>
struct A{
int i = 0;
virtual int foo() {return i;}
};
struct B : A{
int foo() override {return i+2;}
};
using handle_t = std::uintptr_t;
handle_t get(B& a){
return reinterpret_cast<handle_t>(&a);
}
void use(handle_t h){
auto p= reinterpret_cast<A*>(h); //
std::cout << p->foo() << "\n";
}
int main(int argc, char *argv[])
{
B a;
auto h = get(a);
use(h);
return 0;
}
CppReference's page 说可以:
- 将 B* 重新解释为 std::uintptr_t
- reinterpret_cast 从 std::uintptr_t 到 B*(因为它来回是同一类型)
- 将 B* 重新解释为 A*
那么,合并最后两个是否安全?
【问题讨论】:
-
我看不到 cppreference 页面说您可以使用
reinterpret_cast进行向上转换,正如您声称的“从 B* 到 A* 的重新解释”。如果是这样,那就错了。但我认为这里的错误是你的。 -
@Cheersandhth.-Alf 在链接页面 (5) 上说,如果类型别名规则允许,您可以取消引用
reinterpret_cast的结果,在下面(类型别名规则部分),它说如果 "AliasedType 是 DynamicType 的(可能是 cv 限定的)基类" 是允许的(但我并不声称这符合标准措辞)。 -
链接已修复。规则 5(尽管 6 似乎也可以)允许向上转换,其中 T1=B* 和 T2=A* 以及下面的类型别名规则。如果 AliasedType 是 DynamicType 的(可能是 cv 限定的)基类,则从 DynamicType 转换为 AliasedType
-
@Davidbrcz:由于很容易产生一个具有 UB 的反例并且会在常见的编译器中崩溃,所以您可以绝对确定
reinterpret_cast不能用作向上转换。一般来说。最常见的此类示例有A作为 POD 类,B引入了一个虚函数,这可能导致编译器在对象的开头引入一个 vtable 指针。 -
cppreference 更新了适当的指针互转换规则,以添加到派生作为基础的左值访问规则。它可能需要更多的打磨。
标签: c++ casting c++14 reinterpret-cast