2011-02-10 22 views
14

Tengo sentimientos encontrados acerca de static_cast, ya que es el yeso de C++ más seguro disponible, pero permite conversiones seguras e inseguras al mismo tiempo, por lo que debe conocer el contexto para decir si es seguro o podría conducir a UB (por ejemplo, cuando se lanza a una subclase).¿Está mal usado static_cast?

¿Por qué no hay un reparto explícito más seguro? Aquí hay un ejemplo donde podría ser útil. En COM, tienen que devolver el puntero de interfaz como void** ppv, por lo que "tiene que" echar explícitamente

*ppv = (IInterface*) this; 

que luego fue sugerido para ser sustituido por un C más seguro ++ fundido

*ppv = static_cast<IInterface*>(this); 

Pero ¿tiene sentido para hacer incluso un static_cast aquí? this es de una clase que deriva de IInterface, por lo que uno puede simplemente escribir

IInterface* p = this; // implicit conversion to base, safe for sure 
*ppv = p; 

o utilizar un ayudante como

template<class T, class U> 
T implicit_cast(U p) { return p; } 

*ppv = implicit_cast<IInterface*>(this); 

Por lo tanto, es cierto que static_cast a veces se utiliza y puede (debe?) ser reemplazado por este implicit_cast en algunos casos, o me falta algo?

EDIT: Sé que a cast is required in COM, pero no tiene que ser static_cast, un molde implícito sería suficiente.

+1

Nota: Ver http://stackoverflow.com/a/869597 por el "derecho" de la aplicación 'implicit_cast' (y una buena explicación). –

Respuesta

5

En este caso particular, creo que siempre se sabe que la fundición será hacia arriba y que por lo tanto static_cast debe ser perfectamente seguro.

Parece que usar su implicit_cast probablemente sería más seguro, y le permite seleccionar explícitamente a qué clase base desea convertir implícitamente (que aparentemente es necesaria para COM).

Hice una prueba rápida con g ++ y implicit_cast de hecho devuelve diferentes direcciones para diferentes clases base como se esperaba.

Ten en cuenta sin embargo que, en lo que respecta a su primera frase, yo diría que dynamic_cast es, de hecho, más seguro que static_cast ya que devolverá un valor nulo o tirar si el yeso no se puede completar. Por el contrario, static_cast devolverá un puntero de aspecto válido y le permitirá continuar hasta que su programa explote en algún momento en el futuro, sin relación con el reparto incorrecto original.

Programa de prueba:

#include <iostream> 

class B1 
{ 
public: 
    virtual ~B1() {} 
}; 

class B2 
{ 
public: 
    virtual ~B2() {} 
}; 

class Foo : public B1, public B2 
{ 
}; 

template<class T, class U> 
T implicit_cast(U p) { return p; } 

int main() 
{ 
    Foo* f = new Foo; 
    void **ppv = new void*; 

    *ppv = implicit_cast<B1*>(f); 
    std::cout << *ppv << std::endl;; 
    *ppv = implicit_cast<B2*>(f); 
    std::cout << *ppv << std::endl;; 

    return 0; 
} 
+0

De hecho, 'dynamic_cast' sería más seguro que' static_cast' pero no lo mencioné porque nunca lo había visto realmente usado (escuché sobre un golpe de rendimiento pero no sé qué tan grande es). –

+2

@ 7vies: en Visual C++ son alrededor de 2 mil ciclos de procesador y el compilador no lo detectará si convierte su objeto COM al tipo incorrecto; solo obtendrá un puntero nulo durante el tiempo de ejecución. – sharptooth

+0

@sharptooth: Sí, 'dynamic_cast' definitivamente no es la mejor opción en el contexto COM. Ni siquiera estoy seguro de en qué situación podría ser una buena opción, en la mayoría de los casos puede ser reemplazada por polimorfismo en tiempo de ejecución o en tiempo de compilación, que sería más seguro y más rápido al mismo tiempo. –