2008-12-10 10 views
81

No encuentro mucha información en const_cast. La única información que pude encontrar (desbordamiento de pila) es:¿Es const_cast seguro?

la const_cast<>() se utiliza para añadir/quitar const (Ness) (o-dad volátil) de una variable.

Esto me pone nervioso. ¿Podría el uso de un const_cast causar un comportamiento inesperado? ¿Entonces qué?

Alternativamente, ¿cuándo está bien usar const_cast?

+1

La respuesta superior con vistas a algo que podría ser terriblemente obvio, pero merece la pena señalar: Sólo se vuelve insegura _Si se intenta modificar un originalmente 'const' object_ a través de un de-'const' referencia/puntero. Si, en cambio, simplemente estás 'const_cast'ing para trabajar con una API mal especificada (o, en mi caso, perezosamente) que solo acepta una referencia que no sea' 'pero '' solo se usará en los métodos' const' ... No hay problema en lo absoluto. –

Respuesta

89

const_cast es seguro solo si está emitiendo una variable que originalmente no era const. Por ejemplo, si tiene una función que toma un parámetro de const char *, y pasa un char * modificable, es seguro const_cast ese parámetro volver a un char * y modificarlo. Sin embargo, si la variable original era de hecho const, entonces usar const_cast dará como resultado un comportamiento indefinido.

void func(const char *param, size_t sz, bool modify) 
{ 
    if(modify) 
     strncpy(const_cast<char *>(param), sz, "new string"); 
    printf("param: %s\n", param); 
} 

... 

char buffer[16]; 
const char *unmodifiable = "string constant"; 
func(buffer, sizeof(buffer), true); // OK 
func(unmodifiable, strlen(unmodifiable), false); // OK 
func(unmodifiable, strlen(unmodifiable), true); // UNDEFINED BEHAVIOR 
+8

No es cierto. C++ estándar. '§7.1. 5.1/4 dice Excepto que cualquier miembro de clase declarado mutable (7.1.1) se puede modificar, cualquier intento de modificar un objeto const durante su vida útil (3.8) da como resultado un comportamiento indefinido' ** ¡Cualquier intento **! No hay palabras sobre la variable original. –

+18

@Alexey: la variable original es sobre lo que se señala o se hace referencia. Puede tomar una referencia constante a un objeto no const y, por lo tanto, convertirlo en una referencia grabable es un comportamiento bien definido ya que el objeto referido no es realmente const. – Puppy

+0

@DeadMG: 'Puedes tomar una referencia constante a un objeto no const'. Eso es todo. Después de eso tienes algún objeto const en lugar de uno no const. Además, hay casos en los que está permitido crear una copia constante de su objeto inicial no const. Por ejemplo, para el caso del argumento de la función. –

22

Me resulta difícil creer que esa es la única información se podía encontrar sobre const_cast. Citando el second Google hit:

Si desecharon la constness de un objeto que ha sido explícitamente declarada como const, y tratar de modificarlo, los resultados son indefinidos.

Sin embargo, si se desecharon la constness de un objeto que no ha sido declarado explícitamente como const, que puede modificar de forma segura.

+0

Respuesta de Grrrreaat, combine esto con [esta respuesta] (http://stackoverflow.com/questions/357600/is-const-cast-safe/357640#357640) y obtendrá la imagen completa. – bobobobo

+0

hmm.con respecto a la segunda declaración en su respuesta, ¿puedo preguntarle cómo hay una "constidad" para un objeto que no fue declarado explícitamente como const en primer lugar? – hAcKnRoCk

+0

Hay muchas maneras de hacer que un objeto no const sea const, @Iam. Por ejemplo, pase el objeto como un parámetro de referencia constante. O asigne a un puntero-a-const. O use 'const_cast'. O llama a un método const en él. –

5

Estás destruyendo cualquier posibilidad de seguridad en el hilo, si comienzas a modificar las cosas que el compilador creía que eran const.

+1

¿Qué? Si tiene objetos inmutables (const), * trivialmente * puede compartirlos entre hilos. ¡En el instante en que una parte de tu código desecha la constidad, pierdes toda la seguridad de tus hilos! ¿Por qué estoy desfasado para esto? * suspiro * –

+6

Const es sin duda una herramienta útil para hacer código seguro para subprocesos, pero no ofrece garantías (excepto en el caso de las constantes de tiempo de compilación). Dos ejemplos: un objeto const puede tener miembros mutables, y tener un puntero const para un objeto no dice nada sobre si el objeto en sí podría estar cambiando. –

+0

+1 para resolver el problema, aunque :-) –

10

Lo que Adam dice. Otro ejemplo en el que const_cast puede ser útil:

struct sample { 
    T& getT() { 
     return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    } 

    const T& getT() const { 
     /* possibly much code here */ 
     return t; 
    } 

    T t; 
}; 

En primer lugar, añadir const al tipo this puntos a, entonces llamamos a la versión const de getT, y luego quitar const del tipo de retorno, lo cual es válido, ya que t debe ser no const (de lo contrario, no se podría haber llamado a la versión no const de getT). Esto puede ser muy útil si tiene un cuerpo de función grande y desea evitar el código redundante.

+1

Prefiero usar el molde estático para la constness de suma: static_cast (this). Cuando estoy leyendo const_cast significa que el código está haciendo algo potencialmente peligroso, por lo que trato de evitar su uso cuando posible. – mfazekas

+0

a la derecha, el primero puede ser static_cast, o incluso ser implicit_cast (de boost). Lo arreglaré usando el yeso estático. Gracias –

+2

Voy de ida y vuelta si 'const_cast' o' static_cast' es mejor. 'const_cast 'solo puede hacer lo que quiera: cambiar los cv-calificadores.' static_cast' puede 'silenciosamente' realizar otras operaciones que no tenga intención. Sin embargo, el primer lanzamiento es completamente seguro, y 'static_cast' tiende a ser más seguro que' const_cast'. Creo que esta es una situación donde t él 'const_cast' comunica su intención mejor, pero el' static_cast' comunica mejor la seguridad de sus acciones. –

32

Puedo pensar en dos situaciones donde const_cast es seguro y útil (puede haber otros casos válidos).

Una es cuando tiene una instancia, referencia o puntero const, y desea pasar un puntero o referencia a una API que no es const-correcto, pero que está CERTE que no modificará el objeto. Puede const_cast el puntero y pasarlo a la API, confiando en que realmente no cambiará nada. Por ejemplo:

void log(char* text); // Won't change text -- just const-incorrect 

void my_func(const std::string& message) 
{ 
    log(const_cast<char*>(&message.c_str())); 
} 

La otra es que si estás usando un compilador de más edad que no implementa 'mutable', y que desea crear una clase que es, lógicamente, pero no const const bit a bit.Puede const_cast 'this' dentro de un método const y modificar miembros de su clase.

class MyClass 
{ 
    char cached_data[10000]; // should be mutable 
    bool cache_dirty;  // should also be mutable 

    public: 

    char getData(int index) const 
    { 
     if (cache_dirty) 
     { 
      MyClass* thisptr = const_cast<MyClass*>(this); 
      update_cache(thisptr->cached_data); 
     } 
     return cached_data[index]; 
    } 
}; 
+0

Esto ... no parece responder a esta pregunta. Preguntó si 'const_cast' puede causar un comportamiento indefinido, no qué aplicaciones útiles son –

+10

De la pregunta:" Alternativamente, ¿cuándo está bien usar const_cast? " –

+0

Como en "cuando no está indefinido"; él no está buscando ejemplos de cuándo es útil –

7

La respuesta corta es no, no es seguro.

La respuesta larga es que si sabes lo suficiente como para usarlo, entonces debería ser seguro.

Cuando estás lanzando, lo que básicamente dices es "Sé algo que el compilador no sabe". En el caso de const_cast, lo que está diciendo es: "Aunque este método tiene una referencia o puntero no const, sé que no cambiará el parámetro que lo paso".

Así que si realmente sabes lo que afirmas saber al usar el elenco, está bien usarlo.

-1
#include <iostream> 
using namespace std; 

void f(int* p) { 
    cout << *p << endl; 
} 

int main(void) { 
    const int a = 10; 
    const int* b = &a; 

    // Function f() expects int*, not const int* 
    // f(b); 
    int* c = const_cast<int*>(b); 
    f(c); 

    // Lvalue is const 
    // *b = 20; 

    // Undefined behavior 
    // *c = 30; 

    int a1 = 40; 
    const int* b1 = &a1; 
    int* c1 = const_cast<int*>(b1); 

    // Integer a1, the object referred to by c1, has 
    // not been declared const 
    *c1 = 50; 

    return 0; 
} 

fuente: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_const_cast.htm

+0

Esto explica el uso del operador const_cast pero no responde claramente la pregunta. –

+0

Si el compilador se coloca en la memoria de solo lectura, un error al acceder a esta memoria y al sistema operativo completará la aplicación. –

+0

En consecuencia, es seguro usarlo únicamente para las constantes, que se crearon durante el programa, porque estas constantes siempre se colocan en la memoria permitida para la grabación (lectura-escritura). –