Semántica en C ++ de `static const` vs` const`

149

En C ++ específicamente, ¿cuáles son las diferencias semánticas entre, por ejemplo:

static const int x = 0 ;

y

const int x = 0 ;

tanto para staticun enlace como un especificador de clase de almacenamiento (es decir, dentro y fuera de una función).

Clifford
fuente
77
statices probablemente la palabra clave más sobrecargada en C ++. El significado de su código varía ampliamente dependiendo de si está en el alcance del espacio de nombres, en el alcance de la clase o en el alcance de la función. Es posible que desee aclarar eso.
sbi
1
@sbi: pensé que ya lo hice. Alcance de la función (donde es un especificador de clase de almacenamiento) y alcance del archivo (donde es un especificador de vinculación). Los miembros de la clase y las variables de ámbito de espacio de nombres específicamente no me preocupan con respecto a esta pregunta, aunque si alguien siente que hay una distinción interesante, siéntase libre de cubrir eso también.
Clifford
@Clifford: Lamento haber pasado por alto esas últimas palabras. Sin embargo, esto reveló un malentendido de su parte: en C ++, el alcance del archivo es el alcance del espacio de nombres. Si declara algo fuera de cualquier espacio de nombres, simplemente pertenecerá al espacio de nombres global (y es accesible a través de un prefijo ::sin identificador en el frente). No conozco ninguna diferencia significativa entre el espacio de nombres global y cualquier espacio de nombres anidado en él. Ciertamente no hay ninguno con respecto a los staticobjetos.
sbi
1
el enlace es diferente de la visibilidad , al usarlos de manera intercambiable vas a confundir a las personas con las que hablas y probablemente también a ti mismo.
Ben Voigt
1
@Ben, @sbi: no tenía la intención de sugerir que el alcance del archivo y el enlace estático fueran los mismos, simplemente que el enlace estático implica el alcance del archivo. En este sentido, el alcance (o visibilidad) es un atributo de enlace estático y externo, no un sinónimo de ninguno de los dos. Siento que la pregunta original permanece clara y bien formada, y que simplemente estamos discutiendo los comentarios hechos en respuesta al comentario algo condescendiente de sbi. Estamos discutiendo la semántica imprecisa del inglés aquí en lugar de mi comprensión, por lo que creo que podemos detenernos.
Clifford

Respuestas:

128

En el alcance del archivo, no hay diferencia en C ++. consthace que el enlace interno sea el predeterminado, y todas las variables globales tienen una vida útil estática. Pero la primera variante tiene el mismo comportamiento en C, por lo que puede ser una buena razón para usarlo.

Dentro de una función, la segunda versión se puede calcular a partir de parámetros. En C o C ++ no tiene que ser una constante de tiempo de compilación como requieren otros lenguajes.

Dentro de una clase, básicamente lo mismo que para las funciones. Se constpuede calcular un valor de instancia en la lista de inicializadores de ctor . A static constse establece durante la inicialización de inicio y permanece sin cambios para el resto del programa. (Nota: el código para los staticmiembros se ve un poco diferente porque la declaración y la inicialización están separadas).

Recuerde, en C ++, constsignifica solo lectura , no constante . Si tiene un puntero a, constentonces otras partes del programa pueden cambiar el valor mientras no está buscando. Si la variable se definió con const, entonces nadie puede cambiarla después de la inicialización, pero la inicialización puede ser arbitrariamente compleja.

Ben Voigt
fuente
1
¿Hay algo llamado alcance de archivo? Estaba comprobando $ 3.3 y creo que lo más cercano es el 'alcance del espacio de nombres'. ¿Es correcto mi entendimiento? El estándar C ++ 03 menciona el alcance del archivo solo en los Apéndices
Chubsdad
2
Sugeriría que el alcance del archivo es un artefacto del vinculador en lugar del compilador, por lo que es posible que no reciba mucha atención en el lenguaje estándar. Estrictamente es probable que sea "alcance de la unidad de compilación".
Clifford
8
+1 para la frase "const significa solo lectura, no constante", es decir, "Compilador, si ve que alguien intenta modificar esta cosa const, ladre muy fuerte". Esta es la razón por la que algo puede ser constante y volátil al mismo tiempo.
Dan
55
Es más "Compilador, si me ves intenta modificar esta cosa constante (o darle permiso a alguien más para que lo haga)", ladrará muy fuerte. En la mayoría de los contextos, se constaplica a una vista de la variable y no a la variable en sí, otra persona puede tener una no constvista de la misma variable y el compilador se mantendrá en silencio cuando la modifique.
Ben Voigt
1
@Ben: Para ser claros, C ++ 0x no elimina ese uso particular de const, pero lo nuevo constexprse puede usar en su lugar (y también en otros escenarios). En realidad, el estándar C ++ 0x amplía la capacidad de uso consten ese escenario a "tipos literales" no integrales también. Creo que preferiría usar constexprpara esos casos, ya que de todos modos estarías rompiendo la compatibilidad con compiladores anteriores a C ++ 0x.
Michael Burr
4

El borrador estándar de C ++ 17 constimplica staticen el alcance del archivo

Esta es la cita de lo que se mencionó en: https://stackoverflow.com/a/3709257/895245

C ++ 17 n4659 borrador estándar 6.5 "Programa y vinculación":

3 Un nombre que tiene alcance de espacio de nombres (6.3.6) tiene un enlace interno si es el nombre de

  • (3.1) - una variable, función o plantilla de función que se declara explícitamente estática; o,
  • (3.2) - una variable no en línea de tipo calificado const no volátil que no se declara explícitamente como externa ni se ha declarado previamente que tenga enlace externo; o
  • (3.3) - un miembro de datos de una unión anónima.

Anexo C (informativo) Compatibilidad, C.1.2 Cláusula 6: "conceptos básicos" da la razón por la cual esto cambió de C:

6.5 [también 10.1.7]

Cambio: un nombre de ámbito de archivo que se declara explícitamente const, y no se declara explícitamente externo, tiene un enlace interno, mientras que en C tendría un enlace externo.

Justificación: Debido a que los objetos const pueden usarse como valores durante la traducción en C ++, esta característica insta a los programadores a proporcionar un inicializador explícito para cada objeto const. Esta característica permite al usuario colocar objetos constantes en archivos fuente que están incluidos en más de una unidad de traducción.

Efecto sobre la característica original: cambio a la semántica de la característica bien definida.

Dificultad de conversión: transformación semántica.

Qué tan ampliamente utilizado: Raramente.

Ver también: ¿Por qué const implica vinculación interna en C ++, cuando no lo hace en C?

Lo que probablemente quieras hacer en los encabezados

Explicado en detalle en: ¿Qué significa 'const static' en C y C ++?

  • pre C ++ 17: externen encabezado, definición en archivo cpp
  • publicar C ++ 17: variable en línea en el encabezado
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
Gracias, aunque no creo que esta sea una oportunidad en C ++ 17 en comparación con C ++ 98, y la pregunta se hizo en 2010. Además, su respuesta solo trata con static como un especificador de vinculación (en el ámbito del espacio de nombres) , y la pregunta formulada específicamente sobre la semántica en diferentes contextos.
Clifford el
@Clifford sí, definitivamente más antiguo que C ++ 17, solo vago para leer todos los estándares ;-) Aclarará la parte del alcance del archivo.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功