C ++:将整数强制转换为指针的安全方法

时间:2009-12-02 10:24:20

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

我需要将包含地址的整数类型转换为实际的指针类型。我可以按如下方式使用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);

使用第二种方法有什么优势吗?

8 个答案:

答案 0 :(得分:2)

不,这样做没有特别的优势。您使用reinterpret_cast的那一刻,所有赌注都已关闭。这取决于你,以确保演员阵容有效。

答案 1 :(得分:2)

实际上没有什么严重的优势。如果void *指向的东西不是指向多态对象的指针,则会立即遇到未定义的行为(通常是访问冲突)。

答案 2 :(得分:2)

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指向的派生程度最高的对象的指针。

答案 3 :(得分:1)

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

将它们存储为void*的原因是你不会冒失败的风险,比如从整数中创建未对齐的MyClass*指针。

答案 4 :(得分:0)

  • 首先,将int重新解释为void *是一个坏主意。如果sizeof(int)为4且sizeof(void *)为8(64x系统),则表示格式不正确。

  • 此外dynamic_cast仅对多态类的情况有效。

答案 5 :(得分:0)

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

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

void*中使用dynamic_cast是没用的,而且完全错了。您无法使用dynamic_cast检查内存中某个任意位置是否存在有效对象。

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

答案 6 :(得分:0)

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

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

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

Dynamic_Cast用于在类型层次结构中上下移动,而不是来自未知类型。

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

答案 7 :(得分:0)

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

  • 永远不要将指针存储在指针以外的任何内容中
  • 避免使用无效指针
  • 永远不要将指针传递给其他进程
  • 如果您打算在线程上使用指针
  • ,请考虑weak_ptr

原因是:您计划做的是不安全的,除非您与不安全(遗留?)代码接口,否则可以避免。在这种情况下考虑MSalters的答案,但要注意它仍然是一个麻烦。