En la reunión de estándares 2016 de Oulu ISO C ++, el comité de estándares votó una propuesta llamada Variables en línea en C ++ 17.
En términos simples, ¿qué son las variables en línea, cómo funcionan y para qué sirven? ¿Cómo deben declararse, definirse y utilizarse las variables en línea?
const
.inline
palabra clave para las funciones. Lainline
palabra clave, cuando se aplica a las funciones, tiene otro efecto crucial, que se traduce directamente en variables. Unainline
función, que presumiblemente se declara en un archivo de encabezado, no dará como resultado errores de "símbolo duplicado" en el momento del enlace, incluso si el encabezado obtiene#include
d por múltiples unidades de traducción. Lainline
palabra clave, cuando se aplica a las variables, tendrá el mismo resultado exacto. El fin.inline
es solo una solicitud débil y no vinculante para el optimizador. Los compiladores son libres de no solicitar funciones en línea y / o de funciones que no haya anotado. Más bien, el propósito real de lainline
palabra clave es eludir múltiples errores de definición.Respuestas:
La primera oración de la propuesta:
El efecto garantizado de
inline
aplicado a una función es permitir que la función se defina de forma idéntica, con enlaces externos, en múltiples unidades de traducción. Para la práctica, eso significa definir la función en un encabezado, que se puede incluir en varias unidades de traducción. La propuesta extiende esta posibilidad a las variables.Entonces, en términos prácticos, la propuesta (ahora aceptada) le permite usar la
inline
palabra clave para definir unaconst
variable de alcance del espacio de nombres de enlace externo , o cualquierstatic
miembro de datos de clase, en un archivo de encabezado, de modo que las múltiples definiciones que resultan cuando ese encabezado se incluye en múltiples unidades de traducción están bien con el enlazador, solo elige una de ellas.Hasta e incluyendo C ++ 14, la maquinaria interna para esto ha estado allí, con el fin de admitir
static
variables en las plantillas de clase, pero no había una forma conveniente de usar esa maquinaria. Había que recurrir a trucos comoDesde C ++ 17 en adelante, creo que uno puede escribir solo
... en un archivo de encabezado.
La propuesta incluye la redacción
... lo que permite que lo anterior se simplifique aún más a solo
... como señaló TC en un comentario a esta respuesta.
Además, el
constexpr
especificador implica tantoinline
para miembros de datos estáticos como para funciones.Notas:
¹ Para una función
inline
también tiene un efecto indirecto sobre la optimización, que el compilador debería preferir reemplazar las llamadas de esta función con la sustitución directa del código de máquina de la función. Esta sugerencia puede ser ignorada.fuente
Kath::hi
) no tienen que ser constantes.const
restricción se ha eliminado por completo.static std::string const hi = "Zzzzz...";
?Las variables en línea son muy similares a las funciones en línea. Indica al vinculador que solo debe existir una instancia de la variable, incluso si la variable se ve en varias unidades de compilación. El vinculador debe asegurarse de que no se creen más copias.
Las variables en línea se pueden usar para definir globales en bibliotecas de encabezado solamente. Antes de C ++ 17, tenían que usar soluciones alternativas (funciones en línea o hacks de plantillas).
Por ejemplo, una solución alternativa es usar el singleton de Meyer con una función en línea:
Hay algunos inconvenientes con este enfoque, principalmente en términos de rendimiento. Las soluciones de plantilla podrían evitar esta sobrecarga, pero es fácil equivocarse.
Con variables en línea, puede declararlo directamente (sin obtener un error de enlazador de definición múltiple):
Además de las bibliotecas de encabezado solamente, existen otros casos en los que las variables en línea pueden ayudar. Nir Friedman cubre este tema en su charla en CppCon: Lo que los desarrolladores de C ++ deben saber sobre los globales (y el enlazador) . La parte sobre las variables en línea y las soluciones comienza a los 18m9s .
Para resumir, si necesita declarar variables globales que se comparten entre las unidades de compilación, declararlas como variables en línea en el archivo de encabezado es sencillo y evita los problemas con soluciones alternativas anteriores a C ++ 17.
(Todavía hay casos de uso para el singleton de Meyer, por ejemplo, si desea explícitamente tener una inicialización diferida).
fuente
Ejemplo ejecutable mínimo
Esta increíble característica de C ++ 17 nos permite:
constexpr
: ¿Cómo declarar constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Compilar y ejecutar:
GitHub aguas arriba .
Ver también: ¿Cómo funcionan las variables en línea?
C ++ estándar en variables en línea
El estándar C ++ garantiza que las direcciones serán las mismas. C ++ 17 N4659 borrador estándar 10.1.6 "El especificador en línea":
cppreference https://en.cppreference.com/w/cpp/language/inline explica que si
static
no se proporciona, entonces tiene un enlace externo.Implementación variable en línea de GCC
Podemos observar cómo se implementa con:
que contiene:
y
man nm
dice acerca deu
:entonces vemos que hay una extensión ELF dedicada para esto.
Pre-C ++ 17:
extern const
Antes de C ++ 17, y en C, podemos lograr un efecto muy similar con un
extern const
, lo que conducirá a que se use una única ubicación de memoria.Los inconvenientes
inline
son:constexpr
con esta técnica, soloinline
permite eso: ¿Cómo declarar constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub aguas arriba .
Pre-C ++ 17 encabezado solo alternativas
Estos no son tan buenos como la
extern
solución, pero funcionan y solo ocupan una única ubicación de memoria:Una
constexpr
función, porqueconstexpr
implicainline
yinline
permite (fuerza) que la definición aparezca en cada unidad de traducción :y apuesto a que cualquier compilador decente alineará la llamada.
También puede usar una variable entera
const
oconstexpr
estática como en:pero no puede hacer cosas como tomar su dirección, o de lo contrario se usará odr, vea también: https://en.cppreference.com/w/cpp/language/static "Miembros estáticos constantes" y Definiendo datos estáticos constexpr miembros
C
En C la situación es la misma que C ++ pre C ++ 17, he subido un ejemplo en: ¿Qué significa "estático" en C?
La única diferencia es que en C ++,
const
implicastatic
para globales, pero no en C: C ++ semántica de 'static const' vs 'const`¿Alguna forma de alinearlo completamente?
TODO: ¿hay alguna forma de alinear completamente la variable, sin usar memoria alguna?
Muy parecido a lo que hace el preprocesador.
Esto requeriría de alguna manera:
Relacionado:
Probado en Ubuntu 18.10, GCC 8.2.0.
fuente
inline
no tiene casi nada que ver con la alineación, ni para funciones ni para variables, a pesar de la palabra misma.inline
no le dice al compilador que inserte nada en línea. Le dice al enlazador que se asegure de que solo haya una definición, que tradicionalmente ha sido el trabajo del programador. Entonces, "¿Alguna forma de alinearlo completamente?" es al menos una pregunta completamente no relacionada.