【问题标题】:C++: Safe way to cast an integer to a pointerC++:将整数转换为指针的安全方法
【发布时间】:2010-12-22 08:46:02
【问题描述】:

我需要将包含地址的整数类型转换为实际的指针类型。我可以使用 reinterpret_cast 如下:

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);

但是,这不会执行任何运行时检查以查看相关地址是否实际包含 MyClass 对象。我想知道首先转换为 void*(使用 reinterpret_cast)然后在结果上使用 dynamic_cast 是否有任何好处。像这样:

void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);

使用第二种方法有什么好处吗?

【问题讨论】:

  • 第二种方法是不合法的C++,dynamic_cast的表达式类型可能不是void*。
  • 假设整数值最初是指向对象的指针。那么 int 可能无法保存指针。这就是为什么我们有 void*。如果您要为跨无类型边界的传输转换指针,则应将它们转换为 void* 并返回原始类型。
  • 他没有具体说'int',类型可能是intptr_t。
  • @Roger:如果是这样的话,它会起作用。但值得指出的是,使用 void* 是明智的,因为它就是为此而设计的。
  • 那么...如何将指针移过“无类型边界”?就我而言,我收到一条 Win32 消息,需要将 GetWindowLong 调用的结果转换为指针。最安全的方法是什么?

标签: c++ casting dynamic-cast reinterpret-cast


【解决方案1】:

如果您确定the_integer 指向一个已知的基类(至少有一个虚拟成员),那么实际上可能有一个优势:知道该对象属于特定的派生类。但是你必须先reinterpret_cast 到你的基类,然后再做dynamic_cast

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);

dynamic_cast 中使用void* 是没有用的,而且完全是错误的。您不能使用dynamic_cast 来检查内存中任意位置是否存在有效对象。

在非指针类型变量中存储地址时也应该注意。有些架构中 sizeof(void*) != sizeof(int),例如LP64。

【讨论】:

    【解决方案2】:

    在 C++ 中处理指针的最安全方法是类型安全地处理它们。这意味着:

    • 切勿将指针存储在指针以外的任何地方
    • 避免空指针
    • 永远不要将指针传递给其他进程
    • 如果您打算在线程上使用指针,请考虑weak_ptr

    这样做的原因是:您计划做的事情是不安全的,可以避免,除非您与不安全(遗留?)代码交互。在这种情况下,请考虑 MSalters 的回答,但请注意这仍然很麻烦。

    【讨论】:

      【解决方案3】:

      选项 1 是您唯一的(半)便携/有效选项。

      选项 2:作为 dynamic_cast 的 C++ 无效(因为不允许使用 void)。

      在实现级别,它需要来自源类型的类型信息才能到达目标类型。没有办法(或者可能没有办法)从 void* 获取运行时源类型信息,因此这也是无效的。

      Dynamic_Cast 用于向上和向下转换类型层次结构,而不是来自未知类型。

      作为旁注,您可能应该使用 void* 而不是整数来存储无类型指针。 int 可能不够大,无法存储指针。

      【讨论】:

        【解决方案4】:

        实际上并没有太大的优势。如果 void* 指向的不是指向多态对象的指针,那么您会立即遇到未定义的行为(通常是访问冲突)。

        【讨论】:

        • 除非你不这样做。依赖未定义的行为绝不是一个聪明的主意。
        【解决方案5】:
        • 首先“重新解释”intvoid * 是个坏主意。如果sizeof(int) 是 4 而sizeof(void *) 是 8(64x 系统),则它是不正确的。

        • 此外,dynamic_cast 仅对多态类有效。

        【讨论】:

          【解决方案6】:

          dynamic_cast 的类型检查由不同的 C++ 实现以不同的方式实现;如果您想为您的特定实现提供答案,您应该提及您正在使用的实现。一般来说,回答这个问题的唯一方法是参考 ISO 标准 C++。

          根据我对标准的阅读,在 void 指针上调用 dynamic_cast 是非法的:

          dynamic_cast<T>(v)
          

          "如果 T 是指针类型,v 应该是指向完整类类型的指针的右值"

          (来自 ISO C++ 标准的 5.2.7.2)。 void 不是完整的类类型,所以表达式是非法的。

          有趣的是,被转换为的类型被允许是一个空指针,即

          void * foo = dynamic_cast<void *>(some_pointer);
          

          在这种情况下,dynamic_cast 总是成功,结果值是指向v 指向的最衍生对象的指针。

          【讨论】:

          • 这是因为在void* foo = dynamic_cast&lt;void*&gt;(some_pointer); 之后,您可能会找到foo != some_pointer(这意味着 some_pointer 指向一个基础子对象)。
          【解决方案7】:

          安全的方法是记录所有活动的 MyClass 对象。最好将此记录保存在std::set&lt;void*&gt; 中,这意味着您可以轻松添加、删除和测试元素。

          将它们存储为void*s 的原因是您不会冒着从整数中创建未对齐的MyClass* 指针的风险。

          【讨论】:

            【解决方案8】:

            不,这样做没有特别的优势。在您使用reinterpret_cast 的那一刻,所有赌注都已取消。由您来确定演员表是否有效。

            【讨论】:

              猜你喜欢
              • 2012-01-27
              • 1970-01-01
              • 2011-04-03
              • 1970-01-01
              • 1970-01-01
              • 2021-02-13
              • 1970-01-01
              相关资源
              最近更新 更多