2010-08-12 12 views
6

tengo que escribir código para una función de devolución de llamada (que se llamará desde el interior de ATL, pero eso no es realmente importante):¿Puede static_cast convertir un puntero no nulo en un puntero nulo?

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

aquí la void* se garantiza que sea un puntero a CMyClass, por lo static_cast es legal . Mi preocupación es que el código debe ser tan portátil (al menos hasta versiones más nuevas de Visual C++) como sea posible. Entonces, para ser súper paranoico, me inclino a comprobar también el puntero CMyClass*, quiero decir, ¿y si resulta ser nulo?

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

¿El segundo control es razonable? ¿Es posible que static_cast convierta un puntero no nulo en un puntero nulo?

+3

¿Por qué no solo emitir incondicionalmente, y comprobar la nulidad después del reparto? static_cast no va a desreferenciar el puntero. –

+0

@Logan Capaldo: Se siente mejor comprobar lo antes posible. – sharptooth

Respuesta

7

static_cast puede cambiar el valor del puntero, si lanzas entre las partes de un objeto en diferentes compensaciones:

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 

Sin embargo, "El valor de puntero nulo (4.10) se convierte en el valor de puntero nulo del tipo destino " (5.2.9-8), es decir sic es NULL, entonces b es también NULL (y no ajustado) y por lo tanto c2 se establece en NULL. Todo significa que: si la conversión estática de un myObjectVoid no nulo produce NULL, entonces el valor de myObjectVoid se obtuvo eludiendo el sistema de tipo de alguna manera. Y significa que el compilador podría descartar tu segundo cheque porque "de todos modos no puede suceder".

0

El único cambio que static_cast debe hacer en un puntero es para la alineación de palabras. Entonces, en teoría, de myObjectVoid apuntando al último byte en la memoria, es posible que esté "alineado" a 0, pero no veo eso como una preocupación realista.

+0

Si esto fuera posible, ¿no sería un gran problema? Siempre pensé que 0 era el único valor que un puntero válido no podría tener. – ereOn

+0

La verdadera pregunta es si la dirección se redondeará hacia arriba o hacia abajo o si está definida su implementación. –

5

No. Si el puntero se refiere a un objeto válido, y la conversión es válida, entonces el resultado también se referirá a un objeto válido, por lo que no será nulo. Si ninguno es válido, entonces el código es incorrecto y el resultado no está definido. . camino para el uso válido para dar un resultado nulo es comenzar con nula

En el caso específico de la conversión entre los punteros a objetos y punteros void, la norma dice lo siguiente (5.2.9/10):

Un valor de tipo "puntero a objeto" convertido a "puntero a void" y de vuelta al tipo de puntero original tendrá su valor original.

y esto (4,10/3)

El resultado de la conversión de un "puntero a T" a un "puntero a void" puntos del comienzo de la ubicación de almacenamiento donde el objeto de tipo T reside

por lo que los punteros de objeto original y final será el mismo, y el puntero void será nulo si y sólo si los punteros de objeto son.

0

No, el segundo cheque no es razonable. No es posible que static_cast convierta un puntero no nulo en un puntero nulo.Lo único que static_cast puede cambiar sobre el valor provisto en su caso (siendo un puntero) es ajustar la dirección. De lo contrario, está estrictamente relacionado con avisar al resto del análisis de tipo de compilador que el resultado de la expresión debe tratarse como el tipo de destino. Para un puntero, eso significa que la desreferenciación encuentra la dirección correcta dentro del objeto de destino, y que los pasos de incremento y decremento son apropiados para el tamaño del tipo.

+1

Bueno, ahí tienes. En escenarios que no son del mundo real, al pasar un puntero cuidadosamente diseñado a static_cast, se puede ajustar mediante un desplazamiento que lo convierte en NULL. Por supuesto, eso nunca sucederá en la vida real. –

Cuestiones relacionadas