我最近了解到,通过
reinterpret_cast
转换POD的地址将其解释为不同的POD是未定义行为。那么,如果不能用于其名称建议的内容,reinterpret_cast
的潜在用例是什么呢?reinterpret_cast
转换POD的地址将其解释为不同的POD是未定义行为。那么,如果不能用于其名称建议的内容,reinterpret_cast
的潜在用例是什么呢?reinterpret_cast
:
将char*
强制转换为对象指针或反之,用于序列化或与旧版API通信。在这种情况下,从char*
到对象指针的转换在严格意义上仍然是UB(虽然很常见)。实际上你不需要reinterpret_cast
,你可以使用memcpy
代替;但在特定情况下,强制转换可能会避免复制(但在重新解释字节有效的情况下,memcpy
通常也不会产生任何多余的拷贝,编译器足够智能)。
将指针强制转换为std::uintptr_t
或反之,以便在旧版API中进行序列化或执行一些非指针算术运算。这绝对是一种奇怪的方式,在低级代码中也并不经常发生;但考虑这样一种情况,即想要利用在给定平台上指针不使用最高有效位的事实,从而可以将这些位用于存储一些位标志。垃圾收集器实现有时会这样做。如果程序员知道指针始终处于8字节边界上(因此最低三位必须为0),指针的低位有时也可以被利用。
但说实话,我真的记不起来我上次具体、合法地使用reinterpret_cast
是什么时候了。肯定已经是很多年前的事了。
reinterpret_cast
是一种向后续开发人员表达“这可能是未定义行为,但我们必须这样做,因为这是API的工作方式,这里有风险”的方式,以便以一种可搜索的方式呈现。如果是安全的话,你会使用static_cast
。 - Mgetzreinterpret_cast
,至少现在的目的绝对不是为了利用UB。你真的不应该依赖于 UB(忽略一些标准缺陷)。你可以依赖于实现定义的行为,但这是根本不同的。reinterpret_cast
有助于利用实现定义的行为,而不是UB。但你说得对,历史上UB曾经以更加漫不经心的方式对待,一些平台API直接要求UB。 - Konrad Rudolphstatic_cast
绝对是更好的选择,因为它表明了转换结果是定义明确、安全的,并且能够准确地完成预期的操作。如果说有什么问题的话,那么reinterpret_cast
则会给人留下“我不太清楚我在做什么”的印象。总是优先考虑最窄的可用转换,只有在必要时才转向更宽松的转换。 - Konrad Rudolphstatic_cast
可用的情况下,绝对不要使用reinterpret_cast
。即使忽略其他原因,这也容易出错!因为如果你使用static_cast
但意外地尝试转换错误的类型,编译器会阻止你。而使用reinterpret_cast
时,编译器放弃了,并且无法捕获许多愚蠢的错误,而使用static_cast
可以避免这些错误。 - Konrad Rudolphvoid *
参数,并将其转发到回调函数。在两端使用reinterpret_cast
,这样可以保持一切正确。reinterpret_cast
将对象指针转换为/从void*
(你需要它来处理对象,但这是未定义的行为,尽管仍然会被执行)。 - Konrad Rudolphstatic_cast
起作用了(我会说它更可取吗?) - M.Mreinterpret_cast
更可取,尽管你可以使用 static_cast
进行转换。原因是使用 reinterpret_cast
应该总是表示危险。通过 void*
进行转换在我看来始终存在危险点。 - Mgetzvoid*
是一种static_cast
,要撤消隐式转换,您也可以使用static_cast
。这是适当的用法。 - JDługosz
reinterpret_cast
。请使用static_cast
。 - Konrad Rudolphreinterpret_cast
的用例列表链接。请注意,其中大多数用例实际上并不实用。例如,将对象转换为其自身类型或仅允许两种类型之间来回转换,但中间值无法使用(例如,可以将A
转换为B
,但使用B
会导致UB,尽管可以将其转换回A
)。 - François Andrieux