简体   繁体   English

为什么我要使用 dynamic_cast 来强制转换为 void *?

[英]Why would I use dynamic_cast to cast TO a void *?

So I was reading the answers to dynamic_cast from "void *" and although you can't cast from a void * to a T * several of the responses point out that it is possible to cast a T * to a void * , but don't give any indication why you'd want to do that.所以我正在阅读来自 "void *" 的 dynamic_cast的答案,虽然你不能从void *转换为T *一些响应指出可以将T *转换为void * ,但不要没有任何迹象表明你为什么要这样做。

Is this just a bit of trivia that it's possible, or is there a case where it would make sense?这只是可能的一些琐事,还是有可能有意义? I thought about maybe for readability or to make it clear that we're converting to a void * , but given the purpose of dynamic_cast , it doesn't fit very well to me.我考虑过可能是为了可读性或明确表示我们正在转换为void * ,但考虑到dynamic_cast的目的,它不太适合我。

For that matter, is there any reason to do anything other than let T * become void * implicitly?就此而言,除了让T * void *隐式变为void *之外,还有什么理由可以做任何事情吗? I've seen C-style casts to void * used from time to time for this purpose, I presume just to be explicit (assuming we're not doing something unusual like casting int to a pointer or something).我已经看到 C 风格的转换为void *不时用于这个目的,我认为只是明确的(假设我们没有做一些不寻常的事情,比如将int转换为指针或其他东西)。

First, when using dynamic_cast<void*>(x) you get a pointer to the first byte of the most derived object.首先,当使用dynamic_cast<void*>(x)您会得到一个指向最派生对象的第一个字节的指针。 As long as the static type of x is polymorphic.只要x的静态类型是多态的。

This can be useful in a handful of scenarios, where the address serves as object identity:这在少数场景中很有用,其中地址用作对象标识:

  • you now have a way to fully distinguish pointers to subobjects of the same object from pointers to unrelated subobjects.您现在有一种方法可以将指向同一对象的子对象的指针与指向不相关子对象的指针完全区分开来。
  • you can now walk some twisted graphs without visiting the same object several times... which can be used for serialization .您现在可以走一些扭曲的图形,而无需多次访问同一个对象...可用于序列化

Granted, this is certainly not a daily usage , but in C++ the memory address is a de-facto identifier for objects, so a mechanism to access it from any part of the inheritance hierarchy certainly is useful for those few edge cases.当然,这当然不是日常使用,但在 C++ 中,内存地址是对象的事实上的标识符,因此从继承层次结构的任何部分访问它的机制对于那些少数极端情况肯定是有用的。

There is a purpose to this, kinda.这是有目的的,有点。 It is hinted at in the part of the spec that allows it.在允许它的规范部分中暗示了它。 From N3337, section 5.2.7, paragraph 7:来自 N3337,第 5.2.7 节,第 7 段:

If T is “pointer to cv void,” then the result is a pointer to the most derived object pointed to by v.如果 T 是“指向 cv void 的指针”,则结果是指向 v 指向的最派生对象的指针。

So a dynamic_cast<void*>(...) is really shorthand for static_cast<void*>(dynamic_cast<MostDerivedType*>(...)) .所以dynamic_cast<void*>(...)实际上是static_cast<void*>(dynamic_cast<MostDerivedType*>(...))简写。 And that would be useful... sort of.这将是有用的......有点。

The difficulty in making it useful is that you don't necessarily know what MostDerivedType is.使其有用的困难在于您不一定知道MostDerivedType是什么。 After all, it can be different for each expression.毕竟,每个表达式都可能不同。 So once you have it as a void* , you don't necessarily have a way to cast it back safely .因此,一旦将其作为void* ,您就不一定有办法安全地将其恢复。 If you make a guess about MostDerivedType and just static_cast it, and you're wrong , then you're in undefined behavior land.如果您对MostDerivedType进行猜测并且只是static_cast它,并且您错了,那么您就处于未定义的行为领域。 Whereas if you do the dynamic_cast to that type (then static_cast to void* ), it will at least return NULL if it isn't of that type.而如果您对该类型执行dynamic_cast (然后static_castvoid* ),如果它不是该类型,它至少会返回 NULL 。

So no, I would say that it isn't very useful.所以不,我会说它不是很有用。 Not if you want to live within the boundaries of C++ and not rely on potentially undefined behavior.如果您想生活在 C++ 的边界内并且不依赖于潜在的未定义行为,则不是。

It can be useful when implementing wrappers for operators new and delete .它在为运算符newdelete实现包装器时很有用。 The thing is that operator delete allows us to deallocate memory using pointer to a base of a polymorphic object.问题是操作符delete允许我们使用指向多态对象基址的指针来释放内存。 In such situation, the wrapper would not know, which object is really being deallocated there (out of all the objects that were allocated by the wrapper before).在这种情况下,包装器不知道哪个对象真正在那里被释放(在包装器之前分配的所有对象中)。 So we use dynamic_cast< void * >() as unique identity of the object - it casts to the most derived type of a polymorphic object.所以我们使用dynamic_cast< void * >()作为对象的唯一标识 - 它转换为多态对象的最派生类型。 This allow us to keep track of all the objects currently allocated through this wrapper.这允许我们跟踪当前通过此包装器分配的所有对象。 Such wrapper can be used for memory allocation tracking and for batch deallocations.这种包装器可用于内存分配跟踪和批量释放。

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

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