简体   繁体   English

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

[英]C++: Safe way to cast an integer to a pointer

I need to convert an integral type which contains an address to the actual pointer type. 我需要将包含地址的整数类型转换为实际的指针类型。 I could use reinterpret_cast as follows: 我可以按如下方式使用reinterpret_cast:

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

However, this does not perform any run-time checks to see if the address in question actually holds a MyClass object. 但是,这不会执行任何运行时检查,以查看所讨论的地址是否实际包含MyClass对象。 I want to know if there is any benefit in first converting to a void* (using reinterpret_cast) and then using dynamic_cast on the result. 我想知道首先转换为void *(使用reinterpret_cast),然后对结果使用dynamic_cast是否有任何好处。 Like this: 像这样:

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

Is there any advantage in using the second method? 使用第二种方法有什么优势吗?

No, there's no specific advantage in doing so. 不,这样做没有特定的优势。 The moment you use reinterpret_cast , all bets are off. 当您使用reinterpret_cast ,所有赌注都关闭了。 It's up to you to be sure the cast is valid. 由您确定转换是否有效。

Actually no serious advantage. 实际上没有严重的优势。 If the void* points to something that is not a pointer to a polymorphic object you run into undefined behaviour (usually an access violation) immediately. 如果void *指向不是多态对象的指针的对象,则您会立即遇到未定义的行为(通常是访问冲突)。

Type checking on dynamic_cast is implemented in different ways by different C++ implementations; dynamic_cast类型检查由不同的C ++实现以不同的方式实现; if you want an answer for your specific implementation you should mention what implementation you are using. 如果您想为特定的实现提供答案,则应提及您正在使用的实现。 The only way to answer the question in general is to refer to ISO standard C++. 通常,回答该问题的唯一方法是参考ISO标准C ++。

By my reading of the standard, calling dynamic_cast on a void pointer is illegal: 根据我对标准的阅读,在void指针上调用dynamic_cast是非法的:

dynamic_cast<T>(v)

"If T is a pointer type, v shall be an rvalue of a pointer to complete class type" “如果T是指针类型,则v将是完成类类型的指针的右值”

(from 5.2.7.2 of the ISO C++ standard). (来自ISO C ++标准的5.2.7.2)。 void is not a complete class type, so the expression is illegal. void不是完整的类类型,因此该表达式是非法的。

Interestingly, the type being cast to is allowed to be a void pointer, ie 有趣的是,被强制转换为的类型可以是空指针,即

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

In this case, the dynamic_cast always succeeds, and the resultant value is a pointer to the most-derived object pointed to by v . 在这种情况下, dynamic_cast总是成功,并且结果值是v指向最派生对象的指针。

The safe way is to keep a record of all live MyClass objects. 安全的方法是保留所有活动的MyClass对象的记录。 It's best to keep this record in a std::set<void*> , which means you can easily add, remove and test elements. 最好将此记录保存在std::set<void*> ,这意味着您可以轻松地添加,删除和测试元素。

The reason for storing them as void* s is that you don't risk nastyness like creating unaligned MyClass* pointers from your integers. 将它们存储为void*的原因是,您不会像从整数创建未对齐的MyClass*指针那样冒着麻烦。

  • First of all "reinterpreting" int to void * is a bad idea. 首先,将int “重新解释”为void *是一个坏主意。 If sizeof(int) is 4 and sizeof(void *) is 8 (64x system) it is ill-formed. 如果sizeof(int)为4, sizeof(void *)为8(64x系统),则格式错误。

  • Moreover dynamic_cast is valid only for the case of the polymorphic classes. 此外, dynamic_cast仅对多态类有效。

If you know for sure that the_integer points to a known base class (that has at least one virtual member), there might in fact be an advantage: knowing that the object is of a specific derived class. 如果可以肯定地知道the_integer指向一个已知的基类(具有至少一个虚拟成员),则实际上可能会有一个好处:知道对象是特定的派生类。 But you'd have to reinterpret_cast to your base class first and then do the dynamic_cast : 但是您必须先将reinterpret_cast为您的基类,然后再进行dynamic_cast

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

Using a void* in dynamic_cast is useless and simply wrong. dynamic_cast使用void*是没有用的,并且完全是错误的。 You cannot use dynamic_cast to check if there's a valid object at some arbitrary location in memory. 您不能使用dynamic_cast来检查内存中任意位置上是否存在有效对象。

You should also pay attention when storing addresses in non-pointer type variables. 在非指针类型变量中存储地址时,也应注意。 There are architectures where sizeof(void*) != sizeof(int), eg LP64. 有一些体系结构,其中sizeof(void *)!= sizeof(int),例如LP64。

Option 1 is your only (semi) portable/valid option. 选项1是您唯一的(半)便携式/有效选项。

Option 2: is not valid C++ as the dynamic_cast (as void is not allowed). 选项2:作为dynamic_cast无效的C ++(因为不允许void)。

At an implementation level it requires type information from the source type to get to the destination type. 在实现级别,它需要来自源类型的类型信息才能到达目标类型。 There is no way (or there may be no way) to get the runtime source type information from a void* so this is not valid either. 无法(或可能无法)从void *获取运行时源类型信息,因此这也是无效的。

Dynamic_Cast is used to cas up and down the type hierarchy not from unknown types. Dynamic_Cast用于提升和降低类型层次结构,而不是未知类型。

As a side note you should probably be using void* rather than an integer to store an untyped pointer. 附带说明一下,您可能应该使用void *而不是整数来存储无类型的指针。 There is potential for an int not to be large enough to store a pointer. 一个int的大小可能不足以存储指针。

The safest way to handle pointers in C++ is to handle them typesafe. 在C ++中处理指针的最安全方法是处理类型安全的指针。 This means: 这意味着:

  • Never store pointers in anything else than a pointer 切勿将指针存储在指针以外的任何其他位置
  • Avoid void pointers 避免空指针
  • Never pass pointers to other processes 永远不要将指针传递给其他进程
  • consider weak_ptr if you plan to use pointers over threads 如果您打算在线程上使用指针,请考虑weak_ptr

The reason for this is: what you are planning to do is unsafe and can be avoided unless you're interfacing with unsafe (legacy?) code. 原因是:您打算做的事是不安全的,可以避免,除非您与不安全的(旧版)代码交互。 In this case consider MSalters' answer, but be aware that it still is a hassle. 在这种情况下,请考虑MSalters的答案,但请注意,这仍然很麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM