【问题标题】:Is `reinterpret_cast` actually good for anything?`reinterpret_cast` 实际上对任何事情都有好处吗?
【发布时间】:2021-10-05 02:55:13
【问题描述】:

recently learned 认为通过 reinterpret_casting 其地址将 POD 重新解释为不同的 POD 是未定义的行为。所以我只是想知道reinterpret_cast 的潜在用例可能是什么,如果它不能用于它的名字所暗示的那样?

【问题讨论】:

  • @m88 不,您不能为此使用reinterpret_cast。使用static_cast
  • @463035818_is_not_a_number 关于已删除答案的 cmets 中的请求,这里是缺陷报告:open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1839r2.pdf
  • reinterpret_casthere 的用例列表。请注意,这些用例中的大多数实际上都没有用。例如,将一个对象转换为它自己的类型,或者只是允许在两种类型之间来回转换,而中间值否则将无法使用(例如,可以将A 转换为B,但使用B 是UB,不过它可以转换回A)。
  • 如果标题更客观,我认为这个问题不会被关闭(例如“什么是 reinterpret_cast 的明确用例?”。也许重新命名它会看到它重新打开。

标签: c++ casting c++17 reinterpret-cast type-punning


【解决方案1】:

我用过reinterpret_cast有两种情况:

  1. 为了序列化或与旧版 API 通信时与 char* 进行转换。在这种情况下,从char* 到对象指针的转换严格来说仍然是 UB(即使非常频繁地进行)。而且你实际上并不需要 reinterpret_cast ——你可以使用memcpy 代替,但是演员可能在特定情况下避免复制(但在重新解释的情况下字节首先是有效的,memcpy 通常也不会生成任何冗余副本,编译器足够聪明)。

  2. 将指针从/到std::uintptr_t 转换为跨传统 API 序列化它们或对它们执行一些非指针算术。这绝对是一种奇怪的野兽,并且不会经常发生(即使在低级代码中),但考虑到人们想要利用给定平台上的指针不使用最高有效位这一事实的情况,而这些位可以因此用于存储一些位标志。垃圾收集器实现偶尔会这样做。如果程序员知道指针总是对齐的,例如指针的低位有时也可以使用。以 8 字节为边界(因此最低三位必须为 0)。

但老实说,我不记得我实际使用过reinterpret_cast 的最后一个具体、合法的情况。肯定是很多年前的事了。

【讨论】:

  • 我一直认为reinterpret_cast 是一种对后续开发人员说“这可能是未定义的行为,但我们必须这样做,因为这就是这个 API 的工作方式,这里是龙”一个不错的可搜索包。如果它是安全的,你会使用static_cast
  • @Mgetz 这是一个常见的误解。 reinterpret_cast 的目的,至少现在,绝对不是利用 UB。你真的不应该永远依赖 UB(忽略一些标准缺陷)。您可以依赖 实现定义的 行为,但这是根本不同的。 reinterpret_cast 帮助利用实现定义的行为,而不是 UB。但你说得对,从历史上看 UB 过去被以一种更加平淡的方式对待,一些平台 API 完全需要 UB。
  • 我想我的意思是reinterpret_cast 基本上是表明某些东西与龙相关联的好方法,即使它们在技术上不是 UB。例如,通过void* 投射指针之类的事情。是的,您可以使用static_cast 来执行此操作,但对于以下开发人员来说,使用reinterpret_cast 来指示危险是一个更好的指示。
  • @Mgetz 不,为什么会更好?相反,在这种情况下使用static_cast 肯定更好,因为它表明强制转换的结果是明确的、安全的并且完全符合预期。 reinterpret_cast,如果有的话,给人一种“我不知道自己在做什么”的印象。总是更喜欢最窄的可用演员表,只有在必要时才下降到更允许的演员表。
  • 只是为了强调这一点:你应该绝对不使用reinterpret_cast static_cast 工作。即使忽略其他原因,这也容易出错!因为如果您使用 static_cast 但不小心尝试转换错误的类型,编译器会将您从自己手中拯救出来。使用reinterpret_cast,编译器会放弃,并且不会发现许多使用static_cast 可以防止的愚蠢错误。
【解决方案2】:

即使在标准不要求它们这样做的情况下,也允许符合 C 和 C++ 的实现通过有意义的行为来扩展 C 或 C++ 的语义。这样做的实现可能比不这样做的实现更适合更广泛的任务。在许多情况下,使用一致的语法来指定将由设计为适合低级编程任务的实现有意义且一致地处理的构造是有用的,即使未设计的实现也是如此适合这样的目的会毫无意义地处理它们。

【讨论】:

    【解决方案3】:

    一个非常常见的用例是,当您使用 C 库函数时,该函数采用不透明的 void *,该函数被转发到回调函数。在栅栏的两边使用reinterpret_cast,可以这么说,保持一切正常。

    【讨论】:

    • 您不需要reinterpret_cast 将对象指针转换为/从void* (您需要它用于objects,但那是UB,尽管仍然可以)。
    • static_cast 有效(我会说更可取?)
    • @M.M 实际上我会说reinterpret_cast 更可取,尽管您可以使用static_cast 来做到这一点。原因是使用reinterpret_cast 应该始终表示危险。通过void* 投射始终是IMO 的危险点。
    • 隐式转换为void*static_cast,要取消隐式转换,您还可以使用static_cast。这是正确的使用方法。
    猜你喜欢
    • 2010-09-25
    • 2016-09-20
    • 2019-12-29
    • 2011-01-12
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    相关资源
    最近更新 更多