Véndeme en constante corrección

133

Entonces, ¿por qué es exactamente que siempre se recomienda usar const con la mayor frecuencia posible? Me parece que usar const puede ser más un dolor que una ayuda en C ++. Pero, de nuevo, estoy llegando a esto desde la perspectiva de Python: si no quieres que algo cambie, no lo cambies. Dicho esto, aquí hay algunas preguntas:

  1. Parece que cada vez que marco algo como constante, obtengo un error y tengo que cambiar alguna otra función en algún lugar para que también sea constante. Entonces esto hace que tenga que cambiar otra función en otro lugar. ¿Es esto algo que se vuelve más fácil con la experiencia?

  2. ¿Los beneficios de usar const son realmente suficientes 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 momento, estoy más enfocado en los beneficios de usar const para propósitos de corrección y mantenibilidad, aunque también es bueno tener una idea de las implicaciones de rendimiento.

Jason Baker
fuente
1
Retrospectiva de 8 años de antigüedad, pero ... ¿Qué hay de acelerar su código 100x (visto en vivo)?
lorro
1
Verifique mi respuesta aquí (pregunta relacionada, diría la misma respuesta): stackoverflow.com/questions/42310477/… BTW: I loveconst
Gines Hidalgo

Respuestas:

158

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

En pocas palabras, usar const es una buena práctica porque ...

  1. Te protege de cambiar accidentalmente variables que no están destinadas a ser cambiadas,
  2. Le protege de realizar asignaciones variables accidentales, y
  3. El compilador puede optimizarlo. Por ejemplo, estás protegido de

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

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

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

Jordan Parmer
fuente
Siempre supuse que los valores constantes se podían almacenar en caché libremente y así evitar muchos problemas de concurrencia o mejorar la velocidad. ¿Es eso cierto?
Phil H
3
Por supuesto. constLas variables pueden mejorar la velocidad en el sentido de que el compilador puede generar un código más óptimo porque conoce la intención completa y el uso de la variable. ¿Notarás la diferencia? Bueno, eso es discutible sobre su aplicación. 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.
Jordan Parmer
44
A partir de C ++ 11, la biblioteca estándar también supone constque es segura para subprocesos y que el tratamiento de su propio código de esta manera facilita la comprobación de posibles problemas de subprocesos múltiples y es una manera fácil de proporcionar garantías de API para sus usuarios de API.
pmr
3
Para mí, uno de los mayores agregados de valor de la corrección constante es que usted sabe simplemente observando los prototipos de funciones cuando los punteros hacen referencia a datos que nunca son mutados por la función (es decir, solo entrada).
cp.engr
1
No olvides que hay constidad lógica y física . Cualquier objeto agregado contenido que esté marcado como mutable puede cambiar, aunque marcarlo como tal implica que no tiene nada que ver con la coherencia lógica del objeto que lo contiene.
Adrian
128

Aquí hay un fragmento de código con un error común que la corrección constante puede protegerlo contra:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}
Doug T.
fuente
19
Entonces, ¿estamos diciendo que const es necesario porque algún maldito idiota eligió "=" como operador de asignación en C? ;-)
Steve Jessop
37
Por supuesto, la mayoría de los compiladores modernos advierten sobre asignaciones en condicionales y todos
activamos
77
No seas demasiado duro con ese ejemplo: este es el mismo ejemplo evangelizado por algunos desarrolladores para convencernos de que usemos if (0 == i) en lugar de if (i == 0). Por fin, el patrón de código de Doug puede usarse fuera de la declaración "if". Lo importante es que muestra uno de los beneficios del const de una manera humorística. + 1.
paercebal
2
Algunos compiladores (y pelusas) han estado advirtiendo sobre esto durante mucho tiempo, y eso es mucho más útil para detectar este error tipográfico que const: codepad.org/Nnf5JUXV .
77
@Roger asume que vivimos en un mundo donde las construcciones son limpias y sin advertencias. Mi experiencia es que en muchos códigos las advertencias se pierden en el ruido. Además, hay una gran cantidad de código que realiza asignaciones en la expresión if y muchos argumentan que es un estilo válido, "bueno".
Doug T.
62

Parece que cada vez que marco algo como constante, obtengo un error y tengo que cambiar alguna otra función en algún lugar para que también sea constante. Entonces esto hace que tenga que cambiar otra función en otro lugar. ¿Es esto algo que se vuelve más fácil con la experiencia?

Por experiencia, este es un mito total. Ocurre cuando no const-correct se sienta con el código const-correct, claro. Si diseña const-correct desde el principio, esto NUNCA debería ser un problema. Si hace algo constante, y luego algo más no se cumple, el compilador le está diciendo algo extremadamente importante, y debe tomarse el tiempo para arreglarlo correctamente .

Chris Mayer
fuente
77
Esto me ha ayudado a prevenir tantos errores donde tenía una función const a punto de llamar a una función no const porque olvidé que modifica los datos debajo.
Mooing Duck
9
Muy pocas personas siempre comienzan con bases de código limpias. La mayor parte de la codificación es el mantenimiento del 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.
Warren Dew
3
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 constantes en un solo tipo.
Noldorin
44
"Si diseña corrección constante desde el principio", ¿cuántas veces tiene el lujo de forzar la corrección constante desde el principio? La mayoría de nosotros tenemos que lidiar con numerosas API y bibliotecas a diario donde este no es el caso y hay poco que pueda hacer al respecto. Así que estoy de acuerdo con el sentimiento de los OP "Parece que cada vez que marco algo como constante recibo un error" ...
nyholku
@WarrenDew Ese es un argumento transitivo; si los autores originales lo hubieran usado constcorrectamente (es decir, "desde el principio"), entonces no habría problema, ¡ese es exactamente el punto!
Carreras de ligereza en órbita
31

No es para ti cuando escribes el código inicialmente. Es para alguien más (o usted unos meses más tarde) que está mirando la declaración del 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.

Antonio Haley
fuente
1
Esto solo es cierto. Const también se usa como protección para imponer variables internas a través de interfaces, etc.
Jordan Parmer
Lo es, pero puede imponerlo a través de prácticas de codificación disciplinadas, y el cartel dice. El beneficio real proviene de que esto se refleja en la API.
Antonio Haley
2
Exactamente. Es mejor tener "const int Value = 5;" que tener "int ConstValue = 5;". +1.
paercebal
66
El momento adecuado para poner const-correctness es cuando escribe la API inicialmente. De lo contrario, tendrá problemas con el envenenamiento por const cuando lo reemplace (por lo que agregarlo al código antiguo es algo completamente diferente a hacerlo en un código nuevo).
Donal Fellows
@DonalFellows esto no quiere decir poner en constante más tarde. Está diciendo que obtendrá los beneficios más adelante, cuando lea el código con const ya presente
Caleth
27

Si usa const rigurosamente, se sorprenderá de las pocas 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, tiene una sensación cálida en el interior ... validación por compilación ... el reino de la programación funcional está cerca ... casi puede tocarlo ahora ...

QBziZ
fuente
1
desde C ++ 17 y la bondad constexpr estoy escribiendo pruebas de unidad de tiempo de compilación ... cada vez más cerca ...
QBziZ
22

const es una promesa que está haciendo como desarrollador y que cuenta con la ayuda del compilador para hacer cumplir.

Mis razones para ser constante:

  • Se comunica a los clientes de su función que no cambiará la variable u objeto
  • Aceptar argumentos por referencia constante le brinda la eficiencia de pasar por referencia con la seguridad de pasar por valor.
  • Escribir sus interfaces como const correct permitirá a los clientes usarlas. Si escribe su interfaz para tomar referencias que no sean const, los clientes que usan const necesitarán desechar la const para poder trabajar con usted. Esto es especialmente molesto si su interfaz acepta caracteres no constantes * y sus clientes usan cadenas std ::, ya que solo puede obtener un tipo constante * de ellos.
  • El uso de const hará que el compilador lo mantenga honesto para que no cambie por error algo que no debería cambiar.
JohnMcG
fuente
20

Mi filosofía es que si va a utilizar un lenguaje quisquilloso con comprobaciones de tiempo de compilación, haga el mejor uso posible. constes una forma forzada por el compilador de comunicar lo que quiere decir ... es mejor que los comentarios o el doxygen. Estás pagando el precio, ¿por qué no deducir el valor?

Pat Notz
fuente
20

Programar C ++ sin constante es como conducir sin el cinturón de seguridad.

Es difícil ponerse el cinturón de seguridad cada vez que sube al automóvil, y 364 de los 365 días llegará seguro.

La única diferencia es que cuando tenga problemas con su automóvil, lo sentirá de inmediato, mientras que con la programación sin constante puede que tenga que buscar durante dos semanas lo que causó ese accidente solo para descubrir que descuidó inadvertidamente un argumento de función que Has pasado por referencia no constante para la eficiencia.

andreas buykx
fuente
18

Para la programación incrustada, el uso constprudente al declarar estructuras de datos globales puede ahorrar una gran cantidad de RAM al hacer que los datos constantes se ubiquen en ROM o flash sin copiarlos en la RAM en el momento del arranque.

En la programación diaria, el uso constcuidadoso le ayuda a evitar escribir programas que se bloquean o se comportan de manera impredecible porque intentan modificar los literales de cadena y otros datos globales constantes.

Cuando trabaje con otros programadores en proyectos grandes, el uso constadecuado ayuda a evitar que otros programadores lo estrangulen.

bk1e
fuente
13

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

Además, constforma parte del mecanismo de sobrecarga, por lo que puede tener dos métodos con firmas idénticas, pero uno con consty otro sin él. El uno con constse llama para constreferencias, y el otro se llama para no constreferencias.

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;
}
Chris Jester-Young
fuente
13

la corrección constante es una de esas cosas que realmente necesita estar en su lugar desde el principio. Como ha encontrado, es un gran dolor agregarlo más tarde, especialmente cuando hay mucha dependencia entre las nuevas funciones que está agregando y las funciones antiguas no correctas que ya existen.

En gran parte del código que escribo, realmente valió la pena el esfuerzo porque tendemos a usar mucho la composición:

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

Si no tuviéramos una corrección constante, entonces tendría que recurrir a devolver objetos complejos por valor para asegurarse de que nadie estuviera manipulando el estado interno de la clase B a sus espaldas.

En resumen, la corrección constante es un mecanismo de programación defensivo para salvarse del dolor en el futuro.

Peter Kovacs
fuente
7

Digamos que tiene una variable en Python. Sabes que no debes modificarlo. ¿Qué pasa si accidentalmente lo haces?

C ++ te brinda una forma de protegerte de hacer accidentalmente algo que no se suponía que pudieras hacer en primer lugar. Técnicamente puedes evitarlo de todos modos, pero tienes que hacer un trabajo extra para dispararte.

Greg Rogers
fuente
4

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

Ólafur Waage
fuente
3

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 desea cambiar.

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

Wesley Tarle
fuente
2

Me gusta la corrección constante ... en teoría. Cada vez que he tratado de aplicarlo rigurosamente en la práctica, finalmente se ha roto y const_cast comienza a arrastrarse para hacer que el código sea feo.

Tal vez son solo los patrones de diseño que uso, pero const siempre termina siendo un pincel 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 de 'tabla constante', lo que significa que no puede modificar el esquema de la tabla en sí ... pero ¿qué pasa con la manipulación? los datos asociados con la tabla? Si el método Insert () está marcado como constante, internamente tiene que desechar la constante para manipular realmente la base de datos. Si no está marcado como constante, no protege contra la llamada al método AddField.

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

Rob Walker
fuente
Creo que su ejemplo es un caso de uso excesivo de constante, pero no se olvide del modificador mutable, que se puede aplicar a las variables de instancia para eliminar la constante.
Zooba
2
¿Cuándo se marcará una función Insert () const a menos que se la nombre incorrectamente? Agregar cosas generalmente modifica la cosa a la que lo agregaste, lo que significa que no es constante. Lo que realmente quería era un TableWithConstSchema.
Greg Rogers
Podría agregar otra clase, pero no quiero hacer que la API sea innecesariamente compleja por el mero hecho de la corrección constante.
Rob Walker
1

Puede dar al compilador pistas const también ... 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...
}
Keith Nicholas
fuente