2008-09-25 7 views
86

Entonces, ¿por qué exactamente siempre se recomienda usar const tan a menudo como sea posible? Me parece que usar const puede ser más un dolor que una ayuda en C++. Pero, de nuevo, estoy hablando de esto desde la perspectiva de Python: si no quieres que se modifique algo, no lo cambies. Así que con eso dicho, aquí están algunas preguntas:Véndame en const correctness

  1. Parece que cada vez que marcar algo como const, me sale un error y tiene que cambiar alguna otra función en algún lugar para ser const también. Entonces esto me obliga a tener que cambiar otra función en otro lugar. ¿Es esto algo que se vuelve más fácil con la experiencia?

  2. ¿Son las ventajas de usar const realmente suficiente para compensar el problema? Si no tiene la intención de cambiar un objeto, ¿por qué no simplemente no escribir código que no lo cambie?

Debo señalar que en este punto en el tiempo, que estoy más centrado en los beneficios de usar const con fines de corrección y de mantenimiento, aunque también es bueno tener una idea de las implicaciones de rendimiento.

+0

Retrospectiva de 8 años, pero ... ¿Qué le parece acelerar su código 100x (visto en vivo)? – lorro

+1

Compruebe mi respuesta aquí (pregunta relacionada, diría la misma respuesta): http://stackoverflow.com/questions/42310477/declare-value-in-c-header?answertab=active#tab-top BTW: I do love 'const' –

Respuesta

121

Este es el artículo definitivo sobre "const correctness": https://isocpp.org/wiki/faq/const-correctness.

En pocas palabras, el uso de const es una buena práctica porque ...

  1. Te protege de las variables de la modificación accidental que no están destinados ser cambiado,
  2. Te protege de hacer asignaciones variables accidentales, y
  3. El compilador puede optimizarlo. Por ejemplo, usted está protegido de

    if(x = y) // whoops, meant if(x == y) 
    

Al mismo tiempo, el compilador puede generar código más eficiente, ya que sabe exactamente lo que el estado de la variable/función será en todo momento. Si está escribiendo un código C++ estricto, esto es bueno.

Tiene razón en que puede ser difícil usar la precisión constante de forma constante, pero el código de finalización es más conciso y más seguro de programar. Cuando haces un montón de desarrollo en C++, los beneficios de esto se manifiestan rápidamente.

+0

Siempre supuse que los valores de const podían almacenarse libremente en caché y así evitar muchos problemas de concurrencia o mejorar la velocidad. ¿Es eso cierto? –

+2

Claro. Las variables 'const' * pueden * mejorar la velocidad en el sentido de que el compilador puede generar un código más óptimo porque conoce la intención y el uso completos de la variable. ¿Notarás la diferencia? Bueno, eso es discutible en su solicitud. En lo que respecta a la concurrencia, las variables const son de solo lectura, lo que significa que no hay necesidad de bloqueos exclusivos en esas variables ya que el valor siempre será el mismo. –

+2

A partir de C++ 11, la biblioteca estándar asume que 'const' significa seguro para subprocesos y tratar su propio código de esta manera hace que sea más fácil verificar posibles problemas de multithreading y es una manera fácil de proporcionar garantías API para su API usuarios. – pmr

109

Aquí es una pieza de código con un error común que la corrección const se puede proteger contra:

void foo(const int DEFCON) 
{ 
    if (DEFCON = 1)  //< FLAGGED AS COMPILER ERROR! WORLD SAVED! 
    { 
     fire_missiles(); 
    } 
} 
+8

Entonces, estamos diciendo que const es necesario porque algunos idiotas eligieron" = "como el operador de asignaciones en C? ;-) –

+26

Por supuesto, la mayoría de los compiladores modernos advierten sobre las asignaciones en condicionales y todos activamos las advertencias de tratamiento como indicador de errores, derecha: -> –

+0

Por supuesto, dado que foo obtiene su propia copia privada de DEFCON, la verdadera El valor DEFCON no se modificaría de todos modos. – Eclipse

4

hay un buen artículo sobre here const en C++. Es una opinión bastante directa, pero espero que ayude a algunos.

24

No es para usted cuando escribe el código inicialmente. Es para otra persona (o usted unos meses más tarde) que está mirando la declaración de método dentro de la clase o interfaz para ver qué hace. No modificar un objeto es una información importante para obtener de eso.

+1

Esto es solo cierto. Const también se usa como protección para imponer variables in-variables a través de interfaces y demás. –

+0

Lo es, pero puede aplicarlo a través de prácticas de codificación disciplinadas, y los estados del póster.El beneficio real proviene de que esto se refleje en la API. –

+2

Exactamente. Es mejor tener "const int Value = 5;" que tener "int ConstValue = 5;". +1. – paercebal

11

const lo ayuda a aislar el código que "cambia cosas" detrás de su espalda. Entonces, en una clase, marcaría todos los métodos que no cambian el estado del objeto como const.Esto significa que las instancias const de esa clase ya no podrán llamar a ningún método que no sea const. De esta forma, no puede invocar accidentalmente la funcionalidad que puede cambiar su objeto.

Además, const es parte del mecanismo de sobrecarga, por lo que puede tener dos métodos con firmas idénticas, pero uno con const y otro sin él. El que tiene const se llama para las referencias const, y el otro se llama para las referencias que no son const.

Ejemplo:

#include <iostream> 

class HelloWorld { 
    bool hw_called; 

public: 
    HelloWorld() : hw_called(false) {} 

    void hw() const { 
     std::cout << "Hello, world! (const)\n"; 
     // hw_called = true; <-- not allowed 
    } 

    void hw() { 
     std::cout << "Hello, world! (non-const)\n"; 
     hw_called = true; 
    } 
}; 

int 
main() 
{ 
    HelloWorld hw; 
    HelloWorld* phw1(&hw); 
    HelloWorld const* phw2(&hw); 

    hw.hw(); // calls non-const version 
    phw1->hw(); // calls non-const version 
    phw2->hw(); // calls const version 
    return 0; 
} 
1

me gusta corrección const ... en teoría. Por cada vez que he tratado de aplicarlo rigurosamente en la práctica, se ha roto eventualmente y el const_cast comienza a hacer que el código sea feo.

Tal vez solo sean los patrones de diseño que uso, pero const siempre termina siendo un cepillo demasiado ancho.

Por ejemplo, imagine un motor de base de datos simple ... tiene objetos de esquema, tablas, campos, etc. Un usuario puede tener un puntero 'const Table' lo que significa que no puede modificar el esquema de la tabla en sí ... pero ¿qué hay de manipular los datos asociados con la tabla? Si el método Insertar() está marcado const, entonces internamente tiene que descartar la constidad para realmente manipular la base de datos. Si no está marcado const, entonces no protege contra llamar al método AddField.

Quizás la respuesta sea dividir la clase en función de los requisitos de const-ness, pero eso tiende a complicar el diseño más de lo que me gustaría por el beneficio que aporta.

+0

Creo que su ejemplo es un caso de uso excesivo de const, pero no se olvide del modificador mutable, que se puede aplicar a variables de instancia para eliminar la const-sidad. – Zooba

+2

¿Cuándo se marcará una función Insert() const a menos que tenga un nombre incorrecto? Agregar cosas generalmente modifica la cosa a la que lo agregó, lo que significa que no es const. Lo que realmente quería era un TableWithConstSchema. –

+0

Podría agregar otra clase, pero no quiero que la API sea innecesariamente compleja por el mero hecho de la corrección de const. –

2

Cuando usa la palabra clave "const", está especificando otra interfaz para sus clases. Hay una interfaz que incluye todos los métodos y una interfaz que incluye solo los métodos const. Obviamente, esto le permite restringir el acceso a algunas cosas que no quiere cambiar.

Sí, se hace más fácil con el tiempo.

49

Parece que cada vez que marque algo como const, me sale un error y tener que cambiar alguna otra función un lugar para ser const también. Entonces, este me obliga a tener que cambiar otra función en otro lugar. ¿Es esto algo que se vuelve más fácil con experiencia?

Por experiencia, esto es un mito total. Sucede cuando no const-correct se sienta con el código correcto, seguro. Si diseña const-correct desde el principio, esto NUNCA debería ser un problema. Si haces algo const, y luego algo más no cumple, el compilador te dice algo extremadamente importante, y debes tomarte el tiempo para arreglarlo correctamente.

+3

Esto me ha ayudado a prevenir tantos errores en los que tenía una función const llamada a llamar a una función no const porque olvidé que modifica los datos debajo. –

+5

Muy pocas personas siempre comienzan con bases de códigos limpias. La mayoría de la codificación es mantenimiento en código heredado, donde el comentario citado es bastante preciso. Uso const cuando escribo nuevas funciones de hoja, pero me pregunto si vale la pena perseguir cosas a través de media docena o una docena de niveles de llamadas de código desconocido. –

+0

Esto es completamente incorrecto en mi experiencia. Los tipos de puntos anidados crean el mayor dolor de cabeza para este tipo de cosas, donde puede tener múltiples cuantificadores const en un solo tipo. – Noldorin

14

Mi filosofía es que si va a utilizar un lenguaje exigente con comprobaciones de tiempo de compilación que hacer el mejor uso posible, puede hacerlo. const es una forma forzada de compilación de comunicar lo que significa ... es mejor que los comentarios o doxygen alguna vez será. Estás pagando el precio, ¿por qué no derivar el valor?

20

const es una promesa que está haciendo como desarrollador, y alistando la ayuda del compilador en la aplicación.

Mis razones para ser const-corrección:

  • Se comunica a los clientes de su función que el no va a cambiar la variable u objeto
  • argumentos Aceptando por referencia const le da la eficiencia de paso por referencia con la seguridad de pasar por valor.
  • Escribir sus interfaces como const correcto permitirá a los clientes usarlas. Si escribe su interfaz para incluir referencias que no sean const, los clientes que estén utilizando const deberán alejarse de la confusión para poder trabajar con usted. Esto es especialmente molesto si su interfaz acepta caracteres no const * y sus clientes están usando std :: strings, ya que solo puede obtener un const char * de ellos.
  • El uso de const hará que el compilador te mantenga honesto para que no cambies por error algo que no debería cambiar.
12

Para la programación incorporado, usando const juiciosamente al declarar estructuras de datos globales puede ahorrar una gran cantidad de memoria RAM haciendo que los datos constantes que se encuentran en la memoria ROM o Flash sin necesidad de copiar a la memoria RAM en el arranque.

En la programación diaria, usar const le ayuda a evitar escribir programas que se bloquean o se comportan impredeciblemente porque intentan modificar cadenas literales y otros datos globales constantes.

Al trabajar con otros programadores en proyectos grandes, usar const ayuda a evitar que los otros programadores lo estrangulan.

5

Supongamos que tiene una variable en Python. Usted sabe que no está supuesto para modificarlo. ¿Qué pasa si lo haces accidentalmente?

C++ le ofrece una manera de protegerse de hacer algo accidentalmente que se suponía que no podía hacer en primer lugar. Técnicamente puedes evitarlo de todos modos, pero tienes que trabajar más para dispararte a ti mismo.

1

le puede dar los consejos del compilador con const, así .... según el siguiente código

#include <string> 

void f(const std::string& s) 
{ 

} 
void x(std::string& x) 
{ 
} 
void main() 
{ 
    f("blah"); 
    x("blah"); // won't compile... 
} 
16

de programación C++ y sin const es como conducir sin el cinturón de seguridad.

Es muy doloroso ponerse el cinturón de seguridad cada vez que se sube al automóvil, y 364 de los 365 días llegará con seguridad.

La única diferencia es que cuando te metes en problemas con tu automóvil lo sentirás inmediatamente, mientras que con la programación sin const tendrás que buscar durante dos semanas lo que causó ese choque solo para descubrir que te equivocaste inadvertidamente un argumento de función que pasaste por referencia no constante para la eficiencia.

19

Si utiliza const rigurosamente, se sorprenderá de la cantidad de variables reales que hay en la mayoría de las funciones. A menudo no es más que un contador de bucle. Si su código está llegando a ese punto, obtiene una sensación cálida en su interior ... validación mediante compilación ... el ámbito de la programación funcional está cerca ... casi puede tocarlo ahora ...

8

const correctness is one de esas cosas que realmente necesitan estar en su lugar desde el principio. Como ha encontrado, es un gran problema agregarlo más adelante, especialmente cuando existe una gran dependencia entre las nuevas funciones que está agregando y las funciones antiguas que ya no existen.

En una gran parte del código que escribo, es realmente valido la pena el esfuerzo porque se tiende a utilizar la composición mucho:

class A { ... } 
class B { A m_a; const A& getA() const { return m_a; } }; 

Si no tuviéramos const-corrección, entonces se tendría que recurre a devolver objetos complejos por valor para asegurarse de que nadie estaba manipulando el estado interno de la clase B a sus espaldas.

En resumen, const-correctness es un mecanismo de programación defensivo para salvarse del dolor en el camino.

1

También sin corrección de const no puede pasar argumentos por const reference, lo que podría llevar a más copias. La referencia Pass by (no const) no es una solución porque las referencias no const no se pueden vincular a los temporarios.