c++ - www - ¿Por qué usar static_cast<int>(x) en lugar de(int) x?




www c++ (6)

He escuchado que la función static_cast debería preferirse a la static_cast de estilo C o simple. ¿Es esto cierto? ¿Por qué?


En resumen :

  1. static_cast<>() te da una capacidad de compilación de tiempo de compilación, el reparto C-Style no.
  2. static_cast<>() puede verse fácilmente en cualquier lugar dentro de un código fuente de C ++; por el contrario, C_Style cast es más difícil de detectar.
  3. Las intenciones se transmiten mucho mejor utilizando moldes de C ++.

Más explicación :

El reparto estático realiza conversiones entre tipos compatibles . Es similar al elenco de estilo C, pero es más restrictivo. Por ejemplo, la conversión de estilo C permitiría que un puntero entero apunte a un carácter.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Dado que esto da como resultado un puntero de 4 bytes que apunta a 1 byte de la memoria asignada, escribir en este puntero causará un error en tiempo de ejecución o sobrescribirá alguna memoria adyacente.

*p = 5; // run-time error: stack corruption

En contraste con la conversión de estilo C, la conversión estática permitirá que el compilador compruebe que los tipos de datos de puntero y de punta son compatibles, lo que permite al programador detectar esta asignación de puntero incorrecta durante la compilación.

int *q = static_cast<int*>(&c); // compile-time error

Lea más en:
¿Cuál es la diferencia entre static_cast <> y estilo C casting
y
Reparto regular vs. static_cast vs. dynamic_cast


  1. Permite que las conversiones se encuentren fácilmente en su código usando grep o herramientas similares.
  2. Hace que sea explícito el tipo de reparto que estás haciendo, y comprometer la ayuda del compilador para hacerla cumplir. Si solo desea eliminar la constancia, puede utilizar const_cast, que no le permitirá hacer otros tipos de conversiones.
  3. Los cast son intrínsecamente feos: usted como programador está ignorando cómo el compilador trataría normalmente su código. Le estás diciendo al compilador: "Sé mejor que tú". Siendo ese el caso, tiene sentido que realizar un reparto sea algo moderadamente doloroso, y que deberían sobresalir en su código, ya que son una fuente probable de problemas.

Ver la introducción efectiva de C ++


La razón principal es que los modelos C clásicos no distinguen entre lo que llamamos static_cast<>() , reinterpret_cast<>() , const_cast<>() y dynamic_cast<>() . Estas cuatro cosas son completamente diferentes.

Un static_cast<>() suele ser seguro. Existe una conversión válida en el idioma o un constructor apropiado que lo hace posible. La única vez que es un poco arriesgado es cuando desciende a una clase heredada; debe asegurarse de que el objeto sea en realidad el descendiente que dice que es, por medios externos al idioma (como una bandera en el objeto). Un dynamic_cast<>() está seguro siempre que el resultado esté marcado (puntero) o se tenga en cuenta una posible excepción (referencia).

Un reinterpret_cast<>() (o un const_cast<>() ) por otro lado siempre es peligroso. Le dices al compilador: "confía en mí: sé que esto no parece un foo (parece que no es mutable), pero es".

El primer problema es que es casi imposible saber cuál ocurrirá en un reparto de estilo C sin mirar grandes piezas dispersas de código y conocer todas las reglas.

Asumamos estos:

class CMyClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

Ahora, estos dos están compilados de la misma manera:

CMyClass *pMyObject;
pMyObject = static_cast<CMyClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CMyClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

Sin embargo, veamos este código casi idéntico:

CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reinterpret_cast<>
                                                  // and it's wrong!!!

Como puede ver, no hay una manera fácil de distinguir entre las dos situaciones sin saber mucho sobre todas las clases involucradas.

El segundo problema es que los modelos de estilo C son demasiado difíciles de localizar. En expresiones complejas puede ser muy difícil ver moldes de estilo C Es virtualmente imposible escribir una herramienta automatizada que necesita ubicar conversiones de estilo C (por ejemplo, una herramienta de búsqueda) sin un front-end completo de compilador de C ++. Por otro lado, es fácil buscar "static_cast <" o "reinterpret_cast <".

pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is 
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

Eso significa que, no solo los lanzamientos de estilo C son más peligrosos, sino que es mucho más difícil encontrarlos todos para asegurarse de que sean correctos.


Los moldes estilo C son fáciles de perder en un bloque de código. Los modelos de estilo C ++ no solo son una mejor práctica; Ofrecen un grado mucho mayor de flexibilidad.

reinterpret_cast permite conversiones de tipo puntero integrales, sin embargo, puede ser inseguro si se utiliza incorrectamente.

static_cast ofrece una buena conversión para tipos numéricos, por ejemplo, desde enumeraciones a ints o ints a flotantes o cualquier tipo de datos que confíe en el tipo. No realiza ninguna verificación de tiempo de ejecución.

Dynamic_cast, por otro lado, realizará estas comprobaciones marcando cualquier asignación o conversión ambigua. Solo funciona con punteros y referencias e incurre en una sobrecarga.

Hay un par de otros, pero estos son los principales que encontrarás.


Un consejo pragmático: puede buscar fácilmente la palabra clave static_cast en su código fuente si planea ordenar el proyecto.


static_cast, además de manipular los punteros a las clases, también se puede utilizar para realizar conversiones definidas explícitamente en clases, así como para realizar conversiones estándar entre tipos fundamentales:

double d = 3.14159265;
int    i = static_cast<int>(d);




casting