¿Hasta dónde llegas const
? ¿Simplemente realiza funciones const
cuando es necesario o va todo el cerdo y lo usa en todas partes? Por ejemplo, imagine un mutador simple que toma un solo parámetro booleano:
void SetValue(const bool b) { my_val_ = b; }
¿Es eso const
realmente útil? Personalmente, opto por usarlo ampliamente, incluidos los parámetros, pero en este caso me pregunto si vale la pena.
También me sorprendió saber que puede omitir const
de los parámetros en una declaración de función pero puede incluirlo en la definición de la función, por ejemplo:
archivo .h
void func(int n, long l);
archivo .cpp
void func(const int n, const long l)
¿Hay alguna razón para esto? Me parece un poco inusual.
Respuestas:
La razón es que la constante para el parámetro solo se aplica localmente dentro de la función, ya que está trabajando en una copia de los datos. Esto significa que la firma de la función es realmente la misma de todos modos. Sin embargo, probablemente sea un mal estilo hacer esto mucho.
Personalmente, tiendo a no usar const excepto para los parámetros de referencia y puntero. Para los objetos copiados, en realidad no importa, aunque puede ser más seguro ya que indica la intención dentro de la función. Es realmente una decisión judicial. Sin embargo, tiendo a usar const_iterator cuando hago un bucle en algo y no tengo la intención de modificarlo, así que supongo que cada uno es suyo, siempre que se mantenga rigurosamente la corrección constante para los tipos de referencia.
fuente
const
de los prototipos de funciones tiene la ventaja de que no necesita modificar el archivo de encabezado si decide abandonar la parteconst
de implementación más adelante.const
donde hace una diferencia útil".const
siempre que sea posible; Es más expresivo. Cuando leo el código de otra persona, utilizo pequeños indicadores como este para juzgar cuánto cuidado pusieron en escribir su código junto con cosas como números mágicos, comentarios y uso apropiado del puntero, etc.int getDouble(int a){ ++a; return 2*a; }
Prueba esto. Por supuesto,++a
no tiene nada que ver allí, pero se puede encontrar allí en una función larga escrita por más de un programador durante un largo período de tiempo. Sugeriría encarecidamente escribirint getDouble( const int a ){ //... }
que generará un error de compilación al encontrar++a;
.class Foo { int multiply(int a, int b) const; }
en tu encabezado. En su aplicación te importa que se puede prometer que no alteraa
yb
por lo queint Foo::multiply(const int a, const int b) const { }
tiene sentido aquí. (Nota al margen: tanto la persona que llama como la implementación se preocupan por el hecho de que la función no altera suFoo
objeto, por lo tanto, la constante al final de su declaración)"const no tiene sentido cuando el argumento se pasa por valor, ya que no modificará el objeto de la persona que llama".
Incorrecto.
Se trata de auto documentar su código y sus suposiciones.
Si su código tiene muchas personas trabajando en él y sus funciones no son triviales, entonces debe marcar "constante" todo lo que pueda. Al escribir un código de fuerza industrial, siempre debe suponer que sus compañeros de trabajo son psicópatas que intentan ayudarlo de cualquier manera posible (especialmente porque a menudo es usted mismo en el futuro).
Además, como alguien mencionó anteriormente, podría ayudar al compilador a optimizar un poco las cosas (aunque es una posibilidad remota).
fuente
A veces (¡con demasiada frecuencia!) Tengo que desenredar el código C ++ de otra persona. Y todos sabemos que el código C ++ de otra persona es un desastre casi por definición :) Entonces, lo primero que hago para descifrar el flujo de datos local es poner constante en cada definición de variable hasta que el compilador comienza a ladrar. Esto significa también argumentos de valor de calificación constante, ya que son solo variables locales sofisticadas inicializadas por la persona que llama.
Ah, desearía que las variables fueran const de forma predeterminada y se requiriera mutable para las variables no const :)
fuente
[x](){return ++x;}
es un error; mira aquíconst
" por defecto en Rust :)Las siguientes dos líneas son funcionalmente equivalentes:
Obviamente no podrá modificar
a
en el cuerpo defoo
si se define de la segunda manera, pero no hay diferencia desde el exterior.Donde
const
realmente es útil es con parámetros de referencia o puntero:Lo que esto dice es que foo puede tomar un parámetro grande, tal vez una estructura de datos que tiene un tamaño de gigabytes, sin copiarlo. Además, le dice a la persona que llama, "Foo no * cambiará el contenido de ese parámetro". Pasar una referencia constante también permite al compilador tomar ciertas decisiones de rendimiento.
*: A menos que deseche la constidad, pero esa es otra publicación.
fuente
Los const superfluos adicionales son malos desde un punto de vista API:
Poner constantes superfluos adicionales en su código para los parámetros de tipo intrínsecos pasados por el valor satura su API sin hacer ninguna promesa significativa al llamante o al usuario de la API (solo obstaculiza la implementación).
Demasiados 'const' en una API cuando no son necesarios es como " lobo llorón ", eventualmente la gente comenzará a ignorar 'const' porque está por todas partes y no significa nada la mayor parte del tiempo.
El argumento "reductio ad absurdum" para consts adicionales en API es bueno para estos dos primeros puntos, si más parámetros de const son buenos, entonces cada argumento que pueda tener una const, DEBE tener una const. De hecho, si fuera realmente tan bueno, desearía que const sea el valor predeterminado para los parámetros y tenga una palabra clave como "mutable" solo cuando desee cambiar el parámetro.
Así que intentemos poner en constante donde podamos:
Considere la línea de código anterior. La declaración no solo es más abarrotada y más larga y más difícil de leer, sino que tres de las cuatro palabras clave 'const' pueden ser ignoradas de manera segura por el usuario API. Sin embargo, el uso adicional de 'const' ha hecho que la segunda línea sea potencialmente PELIGROSA.
¿Por qué?
Una lectura errónea rápida del primer parámetro
char * const buffer
podría hacerle pensar que no modificará la memoria en el búfer de datos que se pasa; sin embargo, ¡esto no es cierto! El 'const' superfluo puede conducir a suposiciones peligrosas e incorrectas sobre su API cuando se escanea o lee mal rápidamente.Las constantes superfluas también son malas desde el punto de vista de implementación de código:
Si FLEXIBLE_IMPLEMENTATION no es cierto, entonces la API es "prometedora" de no implementar la función de la primera manera a continuación.
Esa es una promesa muy tonta de hacer. ¿Por qué debería hacer una promesa que no brinda ningún beneficio a su interlocutor y solo limita su implementación?
Sin embargo, ambas son implementaciones perfectamente válidas de la misma función, por lo que todo lo que has hecho es atar una mano a la espalda innecesariamente.
Además, es una promesa muy superficial que es fácil (y legalmente eludida).
Mire, lo implementé de esa manera de todos modos, aunque prometí no hacerlo, solo usando una función de contenedor. Es como cuando el chico malo promete no matar a alguien en una película y le ordena a su secuaz que lo mate.
Esas constantes superfluas no valen más que una promesa de un chico malo de la película.
Pero la capacidad de mentir es aún peor:
Me han aclarado que puede no coincidir const en el encabezado (declaración) y el código (definición) mediante el uso de const espuria. Los defensores de const-happy afirman que esto es algo bueno, ya que le permite poner const solo en la definición.
Sin embargo, lo contrario es cierto ... puede poner una constante espuria solo en la declaración e ignorarla en la definición. Esto solo hace que la constante superflua en una API sea más una cosa terrible y una mentira horrible: vea este ejemplo:
Todo lo que hace const superfluo en realidad es hacer que el código del implementador sea menos legible al obligarlo a usar otra copia local o una función de envoltura cuando quiere cambiar la variable o pasar la variable por referencia no const.
Mira este ejemplo. ¿Cuál es más legible? ¿Es obvio que la única razón para la variable adicional en la segunda función es porque algún diseñador de API arrojó una constante superflua?
Ojalá hayamos aprendido algo aquí. Const superfluo es una monstruosidad atormentada API, un fastidio molesto, una promesa superficial y sin sentido, un obstáculo innecesario, y ocasionalmente conduce a errores muy peligrosos.
fuente
void foo(int)
yvoid foo(const int)
son exactamente la misma función, no sobrecargas. ideone.com/npN4W4 ideone.com/tZav9R La const aquí es solo un detalle de implementación del cuerpo de la función, y no tiene ningún efecto en la resolución de sobrecarga. Deje const fuera de la declaración, para una API más segura y ordenada, pero ponga const en la definición , si tiene la intención de no modificar el valor copiado.pi++
cuando se supone que no deben hacerlo.const debería haber sido el valor predeterminado en C ++. Me gusta esto :
fuente
unsigned
debería haber sido el valor predeterminado en C ++. Así:int i = 5; // i is unsigned
ysigned int i = 5; // i is signed
.Cuando codifiqué C ++ para vivir gané todo lo que pude. Usar const es una excelente manera de ayudar al compilador a ayudarte. Por ejemplo, si los valores de retorno de su método pueden salvarlo de errores tipográficos como:
cuando quisiste decir:
Si se define foo () para devolver una referencia no constante:
El compilador felizmente le permitirá asignar un valor al anónimo temporal devuelto por la llamada a la función. Haciéndolo constante:
Elimina esta posibilidad.
fuente
foo() = 42
: error: lvalue requerido como operando izquierdo de la asignaciónconst int foo()
es de un tipo diferente queint foo()
, lo que le trae grandes problemas si está utilizando cosas como punteros de función, sistemas de señal / ranura o boost :: bind.const int& foo()
efectivamente lo mismo queint foo()
, debido a la optimización del valor de retorno?Hay una buena discusión sobre este tema en los viejos artículos del "Gurú de la semana" en comp.lang.c ++. Moderados aquí .
El artículo correspondiente de GOTW está disponible en el sitio web de Herb Sutter aquí .
fuente
Digo const sus parámetros de valor.
Considere esta función con errores:
Si el parámetro número fuera constante, el compilador se detendría y nos advertiría del error.
fuente
Utilizo const en parámetros de función que son referencias (o punteros) que son solo [en] datos y no serán modificados por la función. Es decir, cuando el propósito de usar una referencia es evitar copiar datos y no permitir cambiar el parámetro pasado.
Poner const en el parámetro booleano b en su ejemplo solo pone una restricción en la implementación y no contribuye a la interfaz de la clase (aunque generalmente no se recomienda cambiar los parámetros).
La firma de la función para
y
es lo mismo, lo que explica su .c y .h
Asaf
fuente
Si usa el
->*
o.*
operadores , es imprescindible.Te impide escribir algo como
lo cual casi hice ahora, y que probablemente no haga lo que pretendes.
Lo que pretendía decir era
y si hubiera puesto un
const
intermedioBar *
yp
, el compilador me lo habría dicho.fuente
Ah, uno duro. Por un lado, una declaración es un contrato y realmente no tiene sentido pasar un argumento constante por valor. Por otro lado, si observa la implementación de la función, le da al compilador más oportunidades de optimizar si declara un argumento constante.
fuente
const no tiene sentido cuando el argumento se pasa por valor, ya que no modificará el objeto del llamante.
Se debe preferir const al pasar por referencia, a menos que el propósito de la función sea modificar el valor pasado.
Finalmente, una función que no modifica el objeto actual (esto) puede, y probablemente debería declararse const. Un ejemplo está abajo:
Es una promesa de no modificar el objeto al que se aplica esta llamada. En otras palabras, puede llamar:
Si la función no fuera constante, esto generaría una advertencia del compilador.
fuente
Marcar los parámetros de valor 'const' es definitivamente algo subjetivo.
Sin embargo, en realidad prefiero marcar los parámetros de valor const, como en su ejemplo.
El valor para mí es indicar claramente que la función nunca cambia los valores de los parámetros de la función. Tendrán el mismo valor al principio que al final. Para mí, es parte de mantener un estilo de programación muy funcional.
Para una función corta, podría decirse que es una pérdida de tiempo / espacio tener la 'constante' allí, ya que generalmente es bastante obvio que la función no modifica los argumentos.
Sin embargo, para una función más grande, es una forma de documentación de implementación y el compilador la aplica.
Puedo estar seguro de que si hago algún cálculo con 'n' y 'l', puedo refactorizar / mover ese cálculo sin temor a obtener un resultado diferente porque me perdí un lugar donde se cambia uno o ambos.
Como se trata de un detalle de implementación, no necesita declarar los parámetros de valor const en el encabezado, al igual que no necesita declarar los parámetros de función con los mismos nombres que usa la implementación.
fuente
Puede ser que esto no sea un argumento válido. pero si incrementamos el valor de una variable constante dentro de un compilador de funciones nos dará un error: " error: incremento del parámetro de solo lectura ". eso significa que podemos usar la palabra clave const como una forma de evitar la modificación accidental de nuestras variables dentro de las funciones (que se supone que no debemos hacer / solo lectura). así que si accidentalmente lo hicimos en el compilador en tiempo de compilación nos lo hará saber. Esto es especialmente importante si no eres el único que está trabajando en este proyecto.
fuente
Tiendo a usar const siempre que sea posible. (U otra palabra clave apropiada para el idioma de destino). Lo hago simplemente porque permite que el compilador realice optimizaciones adicionales que de otra forma no podría hacer. Como no tengo idea de cuáles pueden ser estas optimizaciones, siempre lo hago, incluso cuando parece una tontería.
Por lo que sé, el compilador podría ver un parámetro de valor constante y decir: "Oye, esta función no lo modifica de todos modos, así que puedo pasar por referencia y guardar algunos ciclos de reloj". No creo que alguna vez haga algo así, ya que cambia la firma de la función, pero hace el punto. Tal vez hace una manipulación de pila diferente o algo así ... El punto es que no lo sé, pero sí sé que tratar de ser más inteligente que el compilador solo me lleva a avergonzarme.
C ++ tiene algo de equipaje adicional, con la idea de corrección constante, por lo que se vuelve aún más importante.
fuente
const
. Más bien, es una cuestión de indicar la intención dentro de la implementación y capturar thinkoes más tarde (incrementar accidentalmente la variable local incorrecta, porque no fue asíconst
). Paralelamente, también agregaría que los compiladores son muy bienvenidos a cambiar las firmas de funciones, en el sentido de que las funciones pueden integrarse y, una vez integradas, la forma en que funcionan puede cambiarse; agregar o eliminar referencias, hacer literales de 'variables', etc., todos están dentro de la regla como si1. La mejor respuesta basada en mi evaluación:
La respuesta de @Adisak es la mejor respuesta aquí según mi evaluación. Tenga en cuenta que esta respuesta es, en parte, la mejor porque también es la mejor respaldada con ejemplos de código real , además de usar un sonido y una lógica bien pensada.
2. Mis propias palabras (de acuerdo con la mejor respuesta):
const
. Todo lo que hace es:const
todas partes puede dificultar esto.const
innecesariamente desordena el código conconst
s en todas partes, alejando la atención de losconst
s que son realmente necesarios para tener un código seguro.const
es de vital importancia cuando es necesario, y debe usarse, ya que evita los efectos secundarios no deseados con cambios persistentes fuera de la función, y por lo tanto, cada puntero o referencia debe usarseconst
cuando el parámetro es solo una entrada, No es una salida. Utilizandoconst
solo en parámetros pasados por referencia o puntero tiene el beneficio adicional de hacer realmente obvio qué parámetros son punteros o referencias. Una cosa más es sobresalir y decir "¡Cuidado! ¡Cualquier parámetroconst
junto a él es una referencia o un puntero!".3) Palabras de Google (de acuerdo conmigo y la mejor respuesta):
(Desde el " Guía de estilo de Google C ++ ")
Fuente: la sección "Uso de const" de la Guía de estilo de Google C ++: https://google.github.io/styleguide/cppguide.html#Use_of_const . Esta es realmente una sección realmente valiosa, así que lea la sección completa.
Tenga en cuenta que "TotW # 109" significa "Consejo de la semana # 109: significativo
const
en las declaraciones de funciones" , y también es una lectura útil. Es más informativo y menos prescriptivo sobre qué hacer, y según el contexto anterior a la regla de la Guía de estilo de Google C ++const
citada anteriormente, pero como resultado de la claridad que proporcionó, laconst
regla citada arriba se agregó a Google C ++ Guía de estilo.También tenga en cuenta que aunque estoy citando la Guía de estilo de Google C ++ aquí en defensa de mi posición, NO significa que siempre sigo la guía o siempre recomiendo seguirla. Algunas de las cosas que recomiendan son simplemente extrañas, como su
kDaysInAWeek
convención de nomenclatura de estilo para "Nombres constantes" . Sin embargo, todavía es útil y relevante señalar cuando una de las compañías técnicas y de software más exitosas e influyentes del mundo usa la misma justificación que yo y otros como @Adisak hacemos para respaldar nuestros puntos de vista sobre este asunto.4. El linter de Clang
clang-tidy
, tiene algunas opciones para esto:R. Es también digno de mención que la desfibradora de Sonido metálico,
clang-tidy
, tiene una opción,readability-avoid-const-params-in-decls
, descrito aquí , para apoyar la aplicación de una base de código no se utilizaconst
para los parámetros de función pase por valor :Y aquí hay dos ejemplos más que estoy agregando para completar y aclarar:
B. También tiene esta opción:
readability-const-return-type
- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html5. Mi enfoque pragmático de cómo redactaría una guía de estilo al respecto:
Simplemente copiaría y pegaría esto en mi guía de estilo:
[COPIAR / PEGAR INICIO]
const
parámetros de funciones pasados por referencia o puntero cuando sus contenidos (a lo que apuntan) NO se deben cambiar. De esta manera, se vuelve obvio cuando una variable pasada por referencia o puntero se espera que cambie, porque le faltaráconst
. En este caso de usoconst
evita efectos secundarios accidentales fuera de la función.const
en los parámetros de función pasados por valor, ya queconst
no tiene ningún efecto en la persona que llama: incluso si la variable se cambia en la función, no habrá efectos secundarios fuera de la función. Consulte los siguientes recursos para obtener información y justificaciones adicionales:const
en las declaraciones de funciones"const
[es decir,const
en parámetros pasados por valor ] en parámetros de función en declaraciones que no son definiciones (y tenga cuidado de no copiar / pegar un sin sentidoconst
). No tiene sentido e ignorado por el compilador, es ruido visual , y podría engañar a los lectores "( https://abseil.io/tips/109 , énfasis agregado).const
calificadores que tienen un efecto en la compilación son los que se colocan en la definición de la función, NO los que están en una declaración directa de la función, como en una declaración de función (método) en un archivo de encabezado.const
[es decir,const
en variables pasadas por valor ] en valores devueltos por una función.const
de punteros o referencias devueltas por una función depende del implementador , ya que a veces es útil.clang-tidy
opciones anteriores con las siguientes opciones:Aquí hay algunos ejemplos de código para demostrar las
const
reglas descritas anteriormente:const
Ejemplos de parámetros:(algunos se toman prestados de aquí )
const
Ejemplos de tipo de devolución:(algunos se toman prestados de aquí )
[COPIA / PEGAR FINAL]
fuente
En el caso que mencione, no afecta a las personas que llaman de su API, por lo que no se hace comúnmente (y no es necesario en el encabezado). Solo afecta la implementación de su función.
No es algo particularmente malo, pero los beneficios no son tan buenos dado que no afecta su API y agrega tipeo, por lo que generalmente no se hace.
fuente
No uso const para el parámetro de valor pasado. A la persona que llama no le importa si modifica el parámetro o no, es un detalle de implementación.
Lo realmente importante es marcar los métodos como constantes si no modifican su instancia. Haga esto a medida que avanza, porque de lo contrario podría terminar con un montón de const_cast <> o podría encontrar que marcar un método const requiere cambiar mucho código porque llama a otros métodos que deberían haberse marcado const.
También tiendo a marcar variables locales const si no necesito modificarlas. Creo que hace que el código sea más fácil de entender al facilitar la identificación de las "partes móviles".
fuente
En optimizaciones del compilador: http://www.gotw.ca/gotw/081.htm
fuente
Yo uso const donde puedo. Const para parámetros significa que no deben cambiar su valor. Esto es especialmente valioso cuando se pasa por referencia. const for function declara que la función no debería cambiar los miembros de las clases.
fuente
Para resumir:
std::vector::at(size_type pos)
. Lo que es lo suficientemente bueno para la biblioteca estándar es bueno para mí.fuente
_Tmp
todo el tiempo; no quiere esto (en realidad no puede usarlos).Si el parámetro se pasa por valor (y no es una referencia), generalmente no hay mucha diferencia si el parámetro se declara como constante o no (a menos que contenga un miembro de referencia, no es un problema para los tipos integrados). Si el parámetro es una referencia o un puntero, generalmente es mejor proteger la memoria referenciada / apuntada, no el puntero en sí (creo que no puede hacer que la referencia en sí misma sea constante, no es que importe mucho ya que no puede cambiar el árbitro) . Parece una buena idea proteger todo lo que pueda como constante. Puede omitirlo sin temor a cometer un error si los parámetros son solo POD (incluidos los tipos incorporados) y no hay posibilidad de que cambien más a lo largo del camino (por ejemplo, en su ejemplo, el parámetro bool).
No sabía sobre la diferencia de declaración de archivo .h / .cpp, pero tiene sentido. En el nivel de código de máquina, nada es "constante", por lo que si declara una función (en .h) como no constante, el código es el mismo que si lo declara como constante (aparte de las optimizaciones). Sin embargo, le ayuda a alistar al compilador que no cambiará el valor de la variable dentro de la implementación de la función (.ccp). Puede ser útil en el caso cuando está heredando de una interfaz que permite el cambio, pero no necesita cambiar el parámetro para lograr la funcionalidad requerida.
fuente
No pondría constantes parámetros como ese: todos ya saben que un valor booleano (en oposición a un valor booleano) es constante, por lo que agregarlo hará que la gente piense "espera, ¿qué?" o incluso que estás pasando el parámetro por referencia.
fuente
Lo que hay que recordar con const es que es mucho más fácil hacer las cosas const desde el principio, que tratar de ponerlas más tarde.
Use const cuando desee que algo no cambie: es una pista adicional que describe lo que hace su función y qué esperar. ¡He visto muchas API C que podrían funcionar con algunas de ellas, especialmente las que aceptan cadenas c!
Estaría más inclinado a omitir la palabra clave const en el archivo cpp que el encabezado, pero como tiendo a cortarlas y pegarlas, se guardarán en ambos lugares. No tengo idea de por qué el compilador lo permite, supongo que es una cosa del compilador. La mejor práctica es definitivamente poner su palabra clave const en ambos archivos.
fuente
Realmente no hay razón para hacer un parámetro de valor "const" ya que la función solo puede modificar una copia de la variable de todos modos.
La razón para usar "const" es si está pasando algo más grande (por ejemplo, una estructura con muchos miembros) por referencia, en cuyo caso se asegura de que la función no pueda modificarlo; o más bien, el compilador se quejará si intenta modificarlo de la manera convencional. Impide que se modifique accidentalmente.
fuente
El parámetro Const es útil solo cuando el parámetro se pasa por referencia, es decir, ya sea referencia o puntero. Cuando el compilador ve un parámetro const, se asegura de que la variable utilizada en el parámetro no se modifique dentro del cuerpo de la función. ¿Por qué alguien querría hacer un parámetro de valor como constante? :-)
fuente
const
establece claramente: 'No necesito modificar esto, así que estoy declarando eso. Si intento modificarlo más tarde, me da un error en tiempo de compilación para que pueda corregir mi error o desmarcar comoconst
". Por lo tanto, es una cuestión de código de higiene y seguridad. Por todo lo que se necesita para agregar a los archivos de implementación, debería ser algo que la gente haga como un reflejo puro, IMO.Como los parámetros se pasan por valor, no hace ninguna diferencia si especifica const o no desde la perspectiva de la función de llamada. Básicamente, no tiene ningún sentido declarar los parámetros de pasar por valor como const.
fuente
Todos los consts en sus ejemplos no tienen ningún propósito. C ++ es paso por valor por defecto, por lo que la función obtiene copias de esos ints y booleanos. Incluso si la función los modifica, la copia de la persona que llama no se ve afectada.
Así que evitaría concursos adicionales porque
fuente
Sé que la pregunta está "un poco" desactualizada, pero a medida que me cruzo con ella, alguien más puede hacerlo en el futuro ... ... aún dudo que el pobre tipo haga una lista aquí para leer mi comentario :)
Me parece que todavía estamos demasiado limitados a la forma de pensar al estilo C. En el paradigma OOP jugamos con objetos, no con tipos. El objeto const puede ser conceptualmente diferente de un objeto no const, específicamente en el sentido de const lógico (en contraste con bitst-const). Por lo tanto, incluso si la corrección de los parámetros de la función es (quizás) un exceso de cuidado en el caso de los POD, no lo es en el caso de los objetos. Si una función funciona con un objeto const, debería decirlo. Considere el siguiente fragmento de código
ps .: puede argumentar que la referencia (const) sería más apropiada aquí y le da el mismo comportamiento. Pues bien. Simplemente dando una imagen diferente de lo que pude ver en otro lado ...
fuente