Question

I need to write code for a callback function (it will be called from within ATL, but that's not really important):

HRESULT callback( void* myObjectVoid )
{
    if( myObjectVoid == 0 ) {
       return E_POINTER;
    }
    CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
    return myObject->CallMethod();
}

here the void* is guaranteed to be a pointer to CMyClass, so static_cast is legal. My concern is the code must be as portable (to newer versions of Visual C++ at least) as possible. So to be super-paranoic I'm inclined to check the CMyClass* pointer as well - I mean what if it turns out to be null?

    if( myObjectVoid == 0 ) {
       return E_POINTER;
    }
    CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
    if( myObject == 0 ) {
       return E_POINTER;
    }

Is the second check reasonable? Is it possible for static_cast to turn a non-null pointer into a null pointer?

Was it helpful?

Solution

static_cast can change the pointer value, if you cast between object parts on different offsets:

class A{ int x; }; class B{ int y; };
class C : A,B {};

C *c=new C(); 

B *b=c; 
// The B part comes after the A part in C. Pointer adjusted

C *c2=static_cast<C*>(b); 
// Pointer gets adjusted back, points to the beginning of the C part

However, "The null pointer value (4.10) is converted to the null pointer value of the destination type." (5.2.9-8), i.e. if c is NULL, then b is also NULL (and not adjusted) and thus c2 is set to NULL. The whole thing means: if static casting a non-NULL myObjectVoid yields NULL, then the value of myObjectVoid was obtained by circumventing the type system somehow. And it means, that the compiler might throw your second check away because "it can't happen anyway".

OTHER TIPS

No. If the pointer refers to a valid object, and the conversion is valid, then the result will also refer to a valid object, so it won't be null. If either is invalid, then the code is incorrect and the result is undefined. So the only way for valid usage to give a null result is to start with null.

In the specific case of converting between object pointers and void pointers, the standard has this to say (5.2.9/10):

A value of type "pointer to object" converted to "pointer to void" and back to the original pointer type will have its original value.

and this (4.10/3)

The result of converting a "pointer to T" to a "pointer to void" points to the start of the storage location where the object of type T resides

so the original and final object pointers will be the same, and the void pointer will be null if and only if the object pointers are.

The only change static_cast should make to a pointer is for word-alignment. So, in theory, of myObjectVoid pointed to the last byte in memory, it's possible that it might be 'aligned-up" to 0, but I don't see that as a realistic concern.

No, the second check is not reasonable. It is not possible for static_cast to turn a non-null pointer into a null pointer. The only thing static_cast may change about the supplied value in your case (being a pointer) is to adjust the address. Otherwise it's strictly concerned with advising the rest of the compiler's type analysis that the result of the expression should be treated as the target type. For a pointer, that means that dereferencing finds the right address within the target object, and that increment and decrement strides are appropriate to the type's size.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top