www org mapwingis mapwindows mapwindow español c++ refactoring const

c++ - org - ¿Hay algún inconveniente en marcar todas las variables que no modificas const?



mapwindows 5 (6)

Sé que un ejemplo tan pequeño y simple realmente no muestra ningún beneficio enorme para esto, pero parece que sería útil en una base de código más grande donde podría mutar accidentalmente una variable que no debería haber mutado.

El problema es que esto básicamente nunca sucede en realidad.

Por otro lado, la const es una enfermedad que se propagará a través de tu código base como una plaga. Tan pronto como declara una variable const , todas las cosas que necesita en ella deben ser const , por lo que solo deben llamar a las funciones const , y simplemente nunca se detienen.

const no vale ni remotamente el precio que paga por él en la mayoría infinita de las situaciones. Solo hay un par de casos en los que const realmente lo protege (por ejemplo, establecer claves), pero incluso entonces, es discutible si tuviera que ser un imbécil total para intentarlo en primer lugar, y probablemente no valga la pena todas las reglas de idioma y Duplicación de código incesante y metalogic redundante.

const es una buena idea que podría ser agradable en teoría, pero las realidades prácticas son que const es una pérdida total de tiempo y espacio. Quemarlo con fuego.

Después de muchas búsquedas en Google, he encontrado mucho sobre las funciones de marcado y sus parámetros como const , pero no tengo una guía sobre cómo marcar las variables como const .

Aquí hay un ejemplo muy simple:

#include <string> #include <iostream> void example(const std::string& x) { size_t length = x.length(); for (size_t i = 0; i < length; ++i) { std::cout << x.at(i) << std::endl; } } int main() { example("hello"); }

Por que no hacer

size_t length = x.length();

const como

const size_t length = x.length();

¿por convención?

Sé que un ejemplo tan pequeño y simple realmente no muestra ningún beneficio enorme para esto, pero parece que sería útil en una base de código más grande donde podría mutar accidentalmente una variable que no debería haber mutado.

A pesar de ese beneficio, realmente no veo que se use tanto (en las bases de código de C ++ que he visto) o mencionado tanto como hacer que las funciones y sus parámetros const .

¿Hay algún inconveniente en hacer esto además de tener que escribir 5 caracteres adicionales? No he encontrado mucho sobre el tema, y ​​no quiero dispararme en el pie si es un problema tener tantas constantes.


En lugar de este código no estándar:

#import <string> #import <iostream> void example(const std::string& x) { size_t length = x.length(); for (size_t i = 0; i < length; ++i) { std::cout << x.at(i) << std::endl; } } int main() { example("hello"); }

... yo escribiría esto:

#include <string> #include <iostream> using namespace std; void example( string const& s ) { for( char const ch : s ) { cout << ch << ''/n''; } } auto main() -> int { example( "hello" ); }

El lugar principal al que podía agregar const , en relación con el código original, era para la variable ch en el bucle. Creo que eso es bueno. const general, const es deseable porque reduce las posibles acciones de código que uno tiene que considerar, y los bucles basados ​​en rango le permiten tener más const .

El principal inconveniente de usar const para la mayoría de las cosas, es cuando tiene que relacionarse con las API de C.

Entonces, solo hay que tomar algunas decisiones sobre si copiar datos o confiar en la documentación y utilizar un const_cast .

Anexo 1:
Tenga en cuenta que la const en un tipo de retorno evita la semántica de movimientos. Hasta donde sé, Andrei Alexandrescu lo notó por primera vez en su artículo Mojo (C ++ 03 move semantics) en Dr Dobbs Journal:

" [A] const temporal parece un oxímoron, una contradicción en los términos. Visto desde una perspectiva práctica, los temporales const obligan a copiar en el destino.

Entonces, este es un lugar donde uno no debería usar const .

Perdón por haber olvidado mencionar esto originalmente; Me recordó el comentario del usuario bogdan en otra respuesta.

Anexo 2:
En la misma línea (para admitir la semántica de movimientos), si lo último que se hace con un argumento formal es almacenar una copia en algún lugar, entonces, en lugar de pasar por referencia a const , puede ser mejor usar un argumento no const pasado por valor, porque puede ser simplemente movido de.

Es decir, en lugar de

string stored_value; void foo( string const& s ) { some_action( s ); stored_value = s; }

… O la redundancia de optimizado

string stored_value; void foo( string const& s ) { some_action( s ); stored_value = s; } void foo( string&& s ) { some_action( s ); stored_value = move( s ); }

… Considera solo escribir

string stored_value; void foo( string s ) { some_action( s ); stored_value = move( s ); }

Puede ser un poco menos eficiente para el caso del argumento real lvalue, descarta las ventajas de const (restricciones sobre lo que posiblemente podría hacer el código) y rompe una convención uniforme de usar const siempre que sea posible, pero no funciona mal en cualquier situación (que es el objetivo principal, evitar eso) y es un código más pequeño y posiblemente más claro.

Notas :
¹ C ++ estándar no tiene una directiva #import . Además, esos encabezados, cuando se incluyen correctamente, no tienen la garantía de definir size_t en el espacio de nombres global.


Estoy de acuerdo con la mayoría de las respuestas dadas hasta ahora, por otro lado, todavía faltan algunos aspectos.

Al definir interfaces, la palabra clave const es tu amigo. Pero debes saber que también es algo limitado y, a veces, incluso egoísta: esto es lo que yo llamaría sus desventajas.

Echemos otro vistazo de cerca a la pregunta:

¿Hay algún inconveniente en marcar todas las variables que no modificas const? `

Si observa que no modifica algo, puede decir que efectivamente es una constante. También las herramientas de análisis de código pueden detectar esto, incluso su compilador ya lo sabrá. Pero esta observación no debe desencadenar un reflejo add-const en ti.

En su lugar, piensa en la variable en sí, pregunta

  • ¿Es útil en absoluto?
  • ¿También se pretende que sea constante?

A veces, una variable intermedia puede simplemente eliminarse, a veces se puede hacer una pequeña modificación (agregar o eliminar una función) para mejorar el código.

Agregar la palabra clave const puede endurecer su código contra errores en otros lugares, pero también contra cambios en el punto de declaración.

Permítame también agregar una palabra sobre las variables miembro que no cambian. Si decide declarar una variable miembro const , debe inicializarla en la lista de inicializadores del constructor de la clase contenedora, esto amplía las condiciones previas para construir objetos de esta clase.

Así que no agregue const donde su compilador lo permita. No se deje seducir para "petrificar su código" ;-)


No hay inconvenientes para marcar variables que no modifique const .

Sin embargo, hay algunos aspectos positivos: el compilador lo ayudará a diagnosticar cuando modifique involuntariamente una variable que no debería / no quiso decir y el compilador puede (aunque debido al lenguaje const_cast y mutable esto es raro) se genera mejor código.

Por lo tanto, te aconsejo; Usa const donde puedas. No hay inconvenientes y su compilador puede ayudarlo a detectar errores. No hay razón para no hacerlo (a excepción de un poco de escritura extra).

Tenga en cuenta que esto se extiende a las funciones miembro también. Hágalos const cuando pueda: les permite ser utilizados en más contextos y ayuda a los usuarios a razonar sobre el código ("llamar a esta función no modificará el objeto" es información valiosa).


Para la variable local size_t length en un método corto como este, en realidad no importa. La desventaja de la verbosidad adicional se equilibra básicamente con la relativa seguridad de evitar errores tipográficos que modifican accidentalmente la longitud. Haz lo que te indique tu guía de estilo local o tu propio instinto.

Para un método más largo o más complejo, podría ser diferente. Pero, de nuevo, si tiene un método tan complejo que importa, tal vez debería al menos considerar refactorizar su código a partes más simples ... De todos modos, si lee y comprende el código, la sugerencia adicional proporcionada por const es algo irrelevante. agradable pero irrelevante

Ligeramente relacionado, aunque no se lo preguntó: para el parámetro de referencia de su método de example , definitivamente desea const , porque puede necesitar pasar una cadena de const. Solo si desea deshabilitar la cadena de paso constante (porque cree que agregará código para modificarlo), debe omitir el código const .


Puedo pensar en al menos dos inconvenientes:

  • verbosidad: más palabras, más símbolos para procesar, ...
  • inercia: si necesitas modificarla, deberás ir y eliminar esta const

Y ambos valen la pena.

La verbosidad es un argumento a menudo escuchado en contra de lo explícito, sin embargo las personas a menudo confunden la velocidad de lectura con la velocidad de comprensión. Se puede encontrar un equilibrio entre la verbosidad y lo explícito, ciertamente, demasiado verboso puede ahogar información útil, pero demasiado implícito / terso puede no presentar información que deba ser reconstruida / inferida / deducida /.

Personalmente, utilizo un lenguaje con comprobación estática fuertemente tipado para que el compilador detecte mi error lo antes posible; anotar con const es dar información tanto al lector como al compilador. Juzgo que vale la pena los 6 símbolos extra.

En cuanto a la inercia, eliminar const es probablemente solo un pequeño costo del cambio ... y se recompensa al forzarte a ir a todos los lugares donde se usa y revisar el código que lo rodea para asegurarte de que está bien eliminar esta const . La modificación repentina de un dato en particular en una ruta de código donde antes era inmutable requiere asegurarse de que ninguna parte de la ruta de código (o sus llamadores) se basó accidentalmente en esta inmutabilidad.