variables estáticas en una función en línea

Tengo una función que se declara y define en un archivo de encabezado. Este es un problema en sí mismo. Cuando esa función no está en línea, cada unidad de traducción que usa ese encabezado obtiene una copia de la función, y cuando están vinculadas entre sí, se duplican. Lo “corregí” al hacer la función en línea, pero me temo que esta es una solución frágil porque, hasta donde yo sé, el comstackdor no garantiza la alineación, incluso cuando se especifica la palabra clave “en línea”. Si esto no es verdad, por favor corrígeme.

De todos modos, la verdadera pregunta es, ¿qué sucede con las variables estáticas dentro de esta función? ¿Con cuántas copias llego?

Supongo que te estás perdiendo algo, aquí.

función estática?

Declarar una función estática lo hará “oculto” en su unidad de comstackción.

Un nombre que tiene un ámbito de espacio de nombres (3.3.6) tiene un enlace interno si es el nombre de

– una variable, función o plantilla de función que se declara explícitamente estática;

3.5 / 3 – C ++ 14 (n3797)

Cuando un nombre tiene un enlace interno, la entidad a la que denota se puede referir con nombres de otros ámbitos en la misma unidad de traducción.

3.5 / 2 – C ++ 14 (n3797)

Si declara esta función estática en un encabezado, todas las unidades de comstackción, incluido este encabezado, tendrán su propia copia de la función.

El problema es que si hay variables estáticas dentro de esa función, cada unidad de comstackción que incluya este encabezado también tendrá su propia versión personal.

función en línea?

Al declararlo en línea, es un candidato para la alineación (no significa mucho en la actualidad en C ++, ya que el comstackdor se alineará o no, a veces ignorando el hecho de que la palabra clave en línea está presente o ausente):

Una statement de función (8.3.5, 9.3, 11.3) con un especificador en línea declara una función en línea. El especificador en línea indica a la implementación que la sustitución en línea del cuerpo de la función en el punto de llamada es preferible al mecanismo de llamada de función habitual. No se requiere una implementación para realizar esta sustitución en línea en el punto de llamada; sin embargo, incluso si esta sustitución en línea se omite, las otras reglas para las funciones en línea definidas en 7.1.2 se seguirán respetando.

7.1.2 / 2 – C ++ 14 (n3797)

En un encabezado, tiene un efecto secundario interesante: la función en línea se puede definir varias veces en el mismo módulo, y el vinculador simplemente unirá “ellos” en uno (si no fueron incluidos por razones del comstackdor).

Para las variables estáticas declaradas en el interior, el estándar dice específicamente que hay una, y solo una de ellas:

Una variable local estática en una función externa en línea siempre se refiere al mismo objeto.

7.1.2 / 4 – C ++ 98 / C ++ 14 (n3797)

(las funciones son por defecto externas, entonces, a menos que específicamente marque su función como estática, esto se aplica a esa función)

Esto tiene la ventaja de “estático” (es decir, se puede definir en un encabezado) sin sus defectos (existe a lo sumo una vez si no está en línea).

variable local estática?

Las variables locales estáticas no tienen ningún vínculo (no pueden mencionarse por su nombre fuera de su scope), pero tienen una duración de almacenamiento estático (es decir, es global, pero su construcción y destrucción obedecen a reglas específicas).

estática + en línea?

Mezclar en línea y estático tendrá las consecuencias que usted describió (incluso si la función está en línea, la variable estática interna no lo estará, y terminará con tantas variables estáticas como unidades de comstackción, incluida la definición de sus funciones estáticas )

Responda a la pregunta adicional del autor

Desde que escribí la pregunta, la probé con Visual Studio 2008. Intenté activar todas las opciones que hacen que VS actúe de acuerdo con las normas, pero es posible que haya omitido algunas. Estos son los resultados:

Cuando la función es meramente “en línea”, solo hay una copia de la variable estática.

Cuando la función es “estática en línea”, hay tantas copias como unidades de traducción.

La verdadera pregunta ahora es si se supone que las cosas son así, o si esta es una idiosincrasia del comstackdor de Microsoft C ++.

Entonces supongo que tienes algo así:

void doSomething() { static int value ; } 

Debes darte cuenta de que la variable estática dentro de la función, simplemente pone, una variable global oculta a todos menos al scope de la función, lo que significa que solo la función declarada en su interior puede alcanzarla.

Alinear la función no cambiará nada:

 inline void doSomething() { static int value ; } 

Solo habrá una variable global oculta. El hecho de que el comstackdor intente alinear el código no cambiará el hecho de que solo hay una variable oculta global.

Ahora, si su función se declara estática:

 static void doSomething() { static int value ; } 

Entonces es “privado” para cada unidad de comstackción, lo que significa que cada archivo CPP que incluye el encabezado donde se declara la función estática tendrá su propia copia privada de la función, incluida su propia copia privada de la variable oculta global, por lo tanto tantas variables como hay unidades de comstackción que incluyen el encabezado.

Agregar “en línea” a una función “estática” con una variable “estática” dentro:

 inline static void doSomething() { static int value ; } 

tiene el mismo resultado que no agregar esta palabra clave “en línea”, en lo que se refiere a la variable estática interna.

Entonces, el comportamiento de VC ++ es correcto, y está confundiendo el significado real de “en línea” y “estático”.

Creo que el comstackdor crea muchas copias de la variable, pero el enlazador elige una y hace que todas las demás la hagan referencia. Obtuve resultados similares cuando probé un experimento para crear diferentes versiones de una función en línea; si la función no estaba en línea (modo de depuración), todas las llamadas pasaron a la misma función, independientemente del archivo de origen desde el que se llamaron.

Piensa como un comstackdor por un momento, ¿cómo podría ser de otra manera? Cada unidad de comstackción (archivo fuente) es independiente de las demás y se puede comstackr por separado; cada uno debe, por lo tanto, crear una copia de la variable, creyendo que es la única. El enlazador tiene la capacidad de alcanzar esos límites y ajustar las referencias para variables y funciones.

Encontré útil la respuesta de Mark Ransom: el comstackdor crea muchas copias de la variable estática, pero el vinculador elige una y la aplica en todas las unidades de traducción.

En otro lugar encontré esto:

Ver [dcl.fct.spec] / 4

[..] Una función en línea con enlace externo tendrá la misma dirección en todas las unidades de traducción. Una variable local estática en una función externa en línea siempre se refiere al mismo objeto. Un literal de cadena en una función en línea externa es el mismo objeto en diferentes unidades de traducción.

No tengo una copia del estándar para verificar, pero coincide con mi experiencia al examinar el ensamblaje en VS Express 2008

Se supone que es de esta manera. “estático” le dice al comstackdor que desea que la función sea local para la unidad de comstackción, por lo tanto, quiere una copia por unidad de comstackción y una copia de las variables estáticas por instancia de la función.

“en línea” solía decirle al comstackdor que desea que la función esté en línea; hoy en día, simplemente lo toma como “está bien si hay varias copias del código, solo asegúrese de que sea la misma función”. Entonces todos comparten las variables estáticas.

Nota: esta respuesta se escribió en respuesta a la respuesta que el póster original publicó en su cuenta.

Desde que escribí la pregunta, la probé con Visual Studio 2008. Intenté activar todas las opciones que hacen que VS actúe de acuerdo con las normas, pero es posible que haya omitido algunas. Estos son los resultados:

Cuando la función es meramente “en línea”, solo hay una copia de la variable estática.

Cuando la función es “estática en línea”, hay tantas copias como unidades de traducción.

La verdadera pregunta ahora es si se supone que las cosas son así, o si se trata de una ideosincracia del comstackdor de Microsoft C ++.

Creo que terminarás con uno por unidad de traducción. De hecho, tiene muchas versiones de esa función (y su variable estática declarada), una para cada unidad de traducción que incluye el encabezado.

Inline significa que el código ejecutable (instrucciones) está incluido en el código de la función de llamada. El comstackdor puede elegir hacer eso independientemente de si lo solicitó. Eso no tiene ningún efecto sobre las variables (datos) declaradas en la función.

Además de cualquier problema de diseño, todo esto puede implicar, ya que ya está atrapado con él, debe utilizar estática en este caso, no en línea. De esa forma, todos comparten las mismas variables. (Función estática)

Estático significa que una copia se distribuye por todo el progtwig, pero en línea significa que requiere el mismo código por varias veces en el mismo progtwig, por lo que no es posible hacer una variable estática dentro de la función en línea.