有一组关于交叉转换(从转换T1*
到不相关T2*
)的问题,例如this和this。答案通常是这样的:reinterpret_cast
是实现定义的,并且转换到void*
后面static_cast
是明确定义的。然而,我还没有看到任何真实的例子说明reinterpret_cast
使用时会出现什么问题。
有哪些现实生活中的例子可以通过void*
有效而reinterpret_cast
无效?
通过 void* 进行投射而 reinterpret_cast 不起作用的真实示例
如果我将这句话解释为,通过强制转换void*
可以帮助我避免未定义的行为并且reinterpret_cast
没有,那么下面就是一个例子。
reinterpret_cast<TYPE*&>
(指针引用)可能会破坏严格的别名规则(至少发生在 g++ 中)并导致您出现未定义的行为。演示。
但是,static_cast<void*&>
会导致编译器错误并使您免于这种未定义的行为。演示。
我在智能指针中看到过这样的用法:
template<class TYPE>
struct SmartPointer
{
void *p;
TYPE& operator ++ ()
{
(reinterpret_cast<TYPE*&>(p))++; // breaking strict aliasing rule
return *this;
}
}
使用 reinterpret_cast 从 T1* 转换到不相关的 T2* 的定义并不比使用 static_cast 少。实际上,当 T1 和 T2 都是标准布局类型时,它的工作方式相同(参见 5.2.10/7):
当“指向 T1 的指针”类型的纯右值 v 转换为“指向 cv T2 的指针”类型时,结果为 static_cast<cv T2*>(static_cast<cv void*>(v))
对于非标准布局类型,转换结果未指定,但对于 static_cast 也未指定。
我想,只有在这样的人工情况下强制转换非指针类型时,你才能有所作为:
struct Foo
{
};
struct Bar
{
operator void*()
{
return 0;
}
};
int main ()
{
Bar b;
Foo * p1 = static_cast<Foo*>(static_cast<void *>(b)); // ok, Bar::operator void* -> static_cast
Foo * p2 = reinterpret_cast<Foo*>(b); // error, no conversion from Bar to Foo*.
}