Home > front end >  Why do they use reinterpret_cast here?
Why do they use reinterpret_cast here?

Time:10-13

Here's some code from the PhysX examples:

std::vector<PxRigidActor*> actors(nbActors);
scene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC,
                    reinterpret_cast<PxActor**>(&actors[0]), nbActors);

And then in the code of the getActors function they use it like this:

PxU32 NpScene::getActors(PxActorTypeFlags types, PxActor** buffer, PxU32 bufferSize, PxU32 startIndex=0) const
{
   ...
        if ((types & PxActorTypeFlag::eRIGID_STATIC ) && mRigidActors[i]->is<PxRigidStatic>())
        {
            if (virtualIndex >= startIndex)
                buffer[writeCount  ] = mRigidActors[i];
            virtualIndex  ;
        }
        else if ((types & PxActorTypeFlag::eRIGID_DYNAMIC) && mRigidActors[i]->is<PxRigidDynamic>())
        {
            if (virtualIndex >= startIndex)
                buffer[writeCount  ] = mRigidActors[i];
            virtualIndex  ;
        }
   ...
}

mRigidActors is defined as Ps::Array<PxRigidActor*>

The inheritance diagram looks like this:

the inheritance diagram showing pxActor is a base of pxRigidActor

So, my questions are:

  1. I heard that the pointer to the parent class can point to the instance of the child class. Then, why do we need any casting at all? I tried, but without casting it doesn't work.

  2. Is it safe to use reinterpret_cast as it is used here? (I suppose yes, because it's just pointers conversion)

  3. Is there a better solution?

CodePudding user response:

reinterpret_cast<PxActor**>(&actors[0])
is casting the address of the first element of the vector, not casting the element itself.

Furthermore, the called function is treating the pointer as an array. That is, it is casting the .data() of the vector to a different type of element.

You would expect static_cast to be used when navigating between base/derived class references or pointers. But that highlights an issue: The cast might modify the address, if the base class instance is not at the beginning of the derived class! The reinterpet_cast avoids this and just changes the type without changing the value... but if such a value change was necessary, this code would not work right anyway. By casting the "out" parameter's address instead of the value in that address, the code has no idea that anything stored in that slot needs to be adjusted back to the real type.

Since he's casting a pointer to the pointer, the static_cast would not work directly in the same place. It's a double pointer, and that doesn't follow the rule of D* to B*. It would have to write the static_cast as a reference cast, and then take the address of that. Off the top of my head, something like &static_cast<PxActor*&>(actors.data()) (that might have the same issue; I'd have to bang on it to get something working, probably not as a single expression; and I have no intention of trying to do that.)

My guess is that he converted a legacy C cast to reinterpet_cast and didn't think too much about it, or saw that only this one worked (in the same place as the legacy cast).

but why?

The code populates a contiguous collection of the base class pointer. It takes an out parameter instead of returning a vector, and the caller wants that vector defined as a derived type instead of the base type. Normally it should be just fine to keep it as the base class since the behavior is presumably polymorphic.

This is copying from different source collections, with identical code in each branch. It probably ought to be generic, or use the visitor pattern. That would avoid most of the type casting issues.

CodePudding user response:

I heard that the pointer to the parent class can point to the instance of the child class. Then, why do we need any casting at all? I tried, but without casting it doesn't work.

There is an implicit conversion from PxRigidActor* to PxActor* (a derived-to-base pointer conversion), but there is no such relationship between PxRigidActor** and PxActor**

Is it safe to use reinterpret_cast as it is used here? (I suppose yes, because it's just pointers conversion)

The cast is not itself unsafe, but it is undefined behaviour to dereference the pointer created by the cast.

Is there a better solution?

Define actors with an appropriate type in the first place, i.e.

std::vector<PxActor*> actors(nbActors);
scene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC, actors.data(), nbActors);

You can then static_cast<PxRigidActor*> the elements of actors as needed.

  • Related