Para empezar, probablemente sepa que const
puede usarse para hacer que los datos de un objeto o un puntero no sean modificables o ambos.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Sin embargo, también puede usar la sintaxis:
Object const *obj; // same as const Object* obj;
Lo único que parece importar es qué lado del asterisco coloca la const
palabra clave. Personalmente, prefiero poner const
a la izquierda del tipo para especificar que sus datos no se pueden modificar, ya que creo que se lee mejor en mi mentalidad de izquierda a derecha, pero ¿qué sintaxis vino primero?
Más importante aún, ¿por qué hay dos formas correctas de especificar const
datos y en qué situación preferiría o necesitaría una sobre la otra si la hubiera?
Editar:
Parece que esta fue una decisión arbitraria cuando el estándar de cómo los compiladores deberían interpretar las cosas fue redactado mucho antes de que yo naciera. Dado que const
se aplica a lo que está a la izquierda de la palabra clave (¿de manera predeterminada?) Supongo que pensaron que no era perjudicial agregar "accesos directos" para aplicar palabras clave y calificadores de tipo de otras maneras, al menos hasta el momento en que la declaración cambie analizando un * o & ...
Este fue el caso también en C, entonces supongo.
const
después del tipo, por ejemplo, en#define MAKE_CONST(T) T const
lugar de#define MAKE_CONST(T) const T
para queMAKE_CONST(int *)
se expanda correctamente enint * const
lugar deconst int *
.Respuestas:
Esencialmente, la razón por la cual la posición de los
const
especificadores antes de un asterisco no importa es que Kernighan y Ritchie definieron la gramática C de esa manera.La razón por la que definieron la gramática de esta manera era probable que su compilador de C analizara la entrada de izquierda a derecha y terminara de procesar cada token a medida que lo consumía. El consumo del
*
token cambia el estado de la declaración actual a un tipo de puntero. Encuentroconst
después*
significa que elconst
calificador se aplica a una declaración de puntero; encontrarlo antes de que el*
calificador se aplique a los datos apuntados.Debido a que el significado semántico no cambia si el
const
calificador aparece antes o después de los especificadores de tipo, se acepta de cualquier manera.Un tipo similar de caso surge al declarar punteros de función, donde:
void * function1(void)
declara una función que devuelvevoid *
,void (* function2)(void)
declara un puntero de función a una función que devuelvevoid
.Nuevamente, lo que hay que notar es que la sintaxis del lenguaje admite un analizador de izquierda a derecha.
fuente
*
analizador del compilador no sepa que es puntero, por lo tanto, es constante para el valor de los datos. Después * está relacionado con el puntero constante. Brillante. Y finalmente explica por qué puedo hacerloconst char
tan bien comochar const
.const
que siempre venga después de lo que está calificando ... exactamente para que siempre pueda terminar de procesar el constante inmediatamente después de consumirlo. Así que esto parece ser un argumento para prohibir West-Const, en lugar de permitirlo.++
operador? "La oración", en mi humilde opinión, me ayudó a darme cuenta de que no había otra razón en particular que no fuera porque podían hacerlo. Tal vez harían una elección diferente hoy / tal vez no.La regla es:
Prefiero usar const a la derecha de la cosa para ser const solo porque es la forma "original" en que se define const.
Pero creo que este es un punto de vista muy subjetivo.
fuente
Object const *
es un puntero a un objeto const. Si coloca elconst
de la izquierda, se leería como un puntero a un Objeto que es constante, que realmente no fluye muy bien.const
que no es una clase de almacenamiento, pero las personas no son analizadores).Prefiero la segunda sintaxis. Me ayuda a hacer un seguimiento de 'qué' es constante leyendo la declaración de tipo de derecha a izquierda:
fuente
Object const* const
no lo esconst const Object*
. "const" no puede estar a la izquierda, excepto en el caso especial donde tanta gente lo adora. (Ver Heath arriba.)El orden de las palabras clave en una declaración no es tan fijo. Hay muchas alternativas para "el único orden verdadero". Me gusta esto
o debería ser
??
fuente
decl-specifier-seq
es una secuencia dedecl-specifier
s. No hay un orden dado por la gramática, y el número de ocurrencias para cada palabra clave está limitado solo por algunas reglas semánticas (puede tener unoconst
pero doslong
:-)unsigned
es un tipo, igual queunsigned int
yint unsigned
.unsigned long
es otro tipo, igual queunsigned long int
yint long unsigned
. ¿Ves el patrón?;)
. OK, graciasstatic
al revoltijo de palabras, pero solo recientemente los compiladores se quejaron de questatic
debe ser lo primero.La primera regla es usar el formato que requieran sus estándares de codificación locales. Después de eso: poner el
const
frente lleva a un sinfín de confusión cuando están involucrados typedefs, por ejemplo:Si su estándar de codificación permite typedef's de punteros, entonces realmente debería insistir en poner la constante después del tipo. En todos los casos, pero cuando se aplica al tipo, const debe seguir a lo que se aplica, por lo que la coherencia también argumenta a favor del const posterior. Pero las pautas de codificación locales prevalecen sobre todas estas; La diferencia no suele ser lo suficientemente importante como para volver atrás y cambiar todo el código existente.
fuente
const std::string::const_iterator
buena medida;)const IntPtr p1
significar que no sea "puntero entero constante" (es decir, "puntero constante a entero")? Nadie en su sano juicio, incluso sin saber cómoIntPtr
se define, pensaría quep1
es mutable. Y para el caso, ¿por qué alguien asumiría incorrectamente que*p1
es inmutable? Además, poner la constante en cualquier otro lugar (p. Ej.IntPtr const p1
) No cambia la semántica en absoluto.std::vector<T>::const_iterator
, donde no es el iterador el que es constante, sino a lo que apunta).Hay razones históricas por las que se acepta izquierda o derecha. Stroustrup había agregado constante a C ++ en 1983 , pero no llegó a C hasta C89 / C90.
En C ++ hay una buena razón para usar siempre const a la derecha. Serás coherente en todas partes porque las funciones miembro const deben declararse de esta manera:
fuente
const int& getInt();
int& const getInt();
int const& getInt();
es mejor que el equivalente,const int& getInt();
mientrasint& const getInt();
que compararlo es redundante (las referencias ya son constantes) aunque legales y generalmente darán una advertencia. De todos modos, const en una función miembro cambia elthis
puntero en la función deFoo* const
aFoo const* const
.const
en una función miembro no significa en absoluto lo mismo, ¿o esvoid set(int)&;
algún tipo de referencia a una función?