2010-04-20 10 views
36

Como regla general, a menudo se considera una mala práctica usar const_cast<>() en código C++ ya que revela (la mayoría de las veces) un defecto en el diseño.Usos correctos de const_cast <>

Si bien estoy totalmente de acuerdo con esto, sin embargo pregunto cuáles son los casos estaban usando const_cast<>() es bien y la única solución .

Podrían ustedes por favor, dame algunos ejemplos que conoce/encontrado?

Muchas gracias.

Respuesta

16

const_cast también se utiliza para eliminar volatile modificadores, como poner en práctica en este() artículo controversed:

http://www.drdobbs.com/184403766

+0

¡Acabo de aprender algo genial! Muchas gracias ! – ereOn

+0

yo también, +1, ¡gracias! – Sanish

25

Es más o menos diseñado para ser utilizado con las API de legado que no están const correcta es decir, con una función que no puede cambiar eso tiene interfaz no const pero en realidad no mutan nada en la interfaz

0

Sí por supuesto, cuando su código de llamada no puede modificarse y no es const correcto. ¡Debe tenerse en cuenta que solo debe usarlo con llamadas a funciones que, con certeza, no modificarán sus datos!

10

Estoy de acuerdo con su declaración de que su uso normal es porque es necesario para ocultar un 'defecto de diseño'.

IME uno de los escenarios de uso típico es cuando intenta interactuar C++ para el código C existente. Una gran cantidad de código C existente lleva cadenas de C como char * incluso cuando la cadena no se modifica mientras que por lo general están representados como algo que se convierte en un const char * en C++. Esa es una discrepancia de impedancia entre los dos lenguajes que normalmente resolverías usando un const_cast. Por supuesto, es mejor que ser muy asegurarse de que el código que está interconexión con no recibe ninguna idea lindo acerca de cómo modificar los datos que se pasa en.

yo diría que se trata de un código de olores en recién escrito código, pero para interactuar con el código anterior de C y C++, es un mal necesario. Dicho esto, sería extremadamente cuidadoso de código que requiere const_cast por cualquier objeto no-POD ya que es normalmente un problema que debe ser resuelto a nivel de diseño y no el nivel de código.

2

Un uso muy legítima de esto es cuando se tiene tanto una constante y API no const (por const y no objetos, respectivamente const) como en

class Bar { 
    const SomeType& foo() const; 
    SomeType& foo(); 
} 

Entonces ya no queremos duplicar el código en ambas funciones a menudo utilizamos

class Bar { 
    SomeType& foo() { 
     //Actual implementation 
    } 
    const SomeType& foo() const { 
     return const_cast<Bar*>(this)->foo(); 
    } 
}; 

Esto es, por supuesto, asumiendo que foo no hace algo que viola la semántica const.

+2

Tienes que al revés , y puede llevar a un comportamiento indefinido. – GManNickG

+0

cuidado para elaborar? – Jasmeet

+3

La preocupación es que la versión no const de 'foo' podría modificar' this', por lo que es "inseguro" llamarlo a un objeto const que usted haya lanzado a non-const. Es "seguro" llamar a una función de miembro de const en un objeto no const, por lo que la versión de GMan es preferible. Sin embargo, la versión de GMan también puede llevar a un comportamiento indefinido cuando el cliente modifica el valor devuelto, como he comentado en su respuesta. –

16

Como otros han dicho, su propósito principal es eliminar const de los objetos para pasar a las funciones no conformes que usted sabe que no modificarán el argumento.

Hay un truco (por Meyers?) Para evitar la duplicación de código, y se va así:

struct foo 
{ 
    const return_type& get(void) const 
    { 
     // fancy pants code that you definitely 
     // don't want to repeat 

     return theValue; // and got it 
    } 

    return_type& get(void) 
    { 
     // well-defined: Add const to *this, 
     // call the const version, then 
     // const-cast to remove const (because 
     // *this is non-const, this is ok) 
     return const_cast<return_type&>(static_cast<const foo&>(*this).get()); 
    } 
}; 
+7

Creo que este truco casi siempre es peor que duplicar el contenido de 'get() const' en' get() '. En los casos en que esto es mejor que copiar y pegar, una plantilla auxiliar (instanciada una vez para const y una para no const) sería aún mejor, ya que le permitiría al compilador verificar que el código de fantasía realmente devuelve algo modificable en el caso donde 'this' es modificable. Puede que no, a veces puede devolver una referencia a una variable global 'const', por lo que este truco te obliga a verificar manualmente la const-correctness de los elegantes pantalones del código. Malo. –

+1

@Steve: Prefiero hacer esto copiar pegar. En el caso especial donde este truco no funcionará, no lo use. – GManNickG

+1

¿Qué pasa si el código de "pantalones elegantes" es 0 líneas, y 'get' simplemente devuelve un miembro de datos? ¿Evitarías copiar y pegar entonces? Mi reclamo es que no hay buenos casos para este truco.O el código es lo suficientemente simple para copiar y pegar, o de lo contrario es demasiado complejo para analizar manualmente la corrección de const. No hay un terreno intermedio que sea demasiado para copiar, pero lo suficientemente pequeño como para que no desee la corrección automática de const. En el ejemplo IIRC de Meyer, el código de pantalones de lujo es una verificación de límites: así que ponga el cheque en una función auxiliar, de la misma forma en que normalmente compartimos el código ;-) –

4

Una legítimo uso (en mi opinión) es con iteradores std::set. Siempre son const, para evitar el cambio de la clave utilizada en el conjunto. Cambiar la clave rompería la estructura interna del conjunto y provocaría un comportamiento indefinido.

Sin embargo, mientras la clave no cambie, es seguro cambiar otros datos en el objeto.

Digamos que usted tiene una std::set así:

std::set<MyObject> some_set; 

Y una clase como esta:

class MyObject { 
    public: 
     MyObject(const std::string &key) 
      : key_(key) {} 

     bool operator<(const MyObject &other) const { 
      return key_ < other.key_; 
     } 

    private: 
     // ... 
     // <some other data> 
     // ... 

     const std::string key_; 
}; 

En el ejemplo anterior, la tecla ya está const, por lo que incluso si modificar el objeto, no se puede romper la estructura interna del conjunto.

Normalmente sólo se puede obtener una referencia const de un iterador de conjunto:

const MyObject &object = *some_set_iterator; 

Pero ya que la clave es const, que es seguro const_cast el iterador sin referencia:

MyObject &object = const_cast<MyObject &>(*some_set_iterator); 
Cuestiones relacionadas