c++ - funciones - limites en varias variables por trayectorias
¿Las variables en línea son únicas a través de los límites? (3)
¿Existe alguna garantía con respecto a la singularidad de una variable en línea cuando se usa a través de límites o es simplemente un detalle de implementación en el que no debo confiar?
Depende de usted asegurar esto (asegurándose de que todas las declaraciones sean, de hecho, las mismas).
El compilador obviamente no puede verificar esto y el enlazador no molesta. Entonces, si le mientes al vinculador (al no hacer lo anterior), terminarás en problemas.
De acuerdo, ya que no todos entienden lo que quiero decir con ''mentirle al vinculador'', lo haré un poco.
@oliv amablemente proporcionó here , que entre otras cosas dice esto (comentario mío):
Las copias duplicadas de estas construcciones [es decir, las variables declaran en línea en varias TU] se descartarán en el momento del enlace.
Lo cual está bien, eso es lo que necesitamos. La cosa es que no sabes cuáles (obviamente, solo se retiene una, por lo que, por extensión, no sabes cuál será).
Entonces, si difieren , no sabes con cuál de ellos vas a terminar y, por lo tanto, lo que obtienes es (una forma particularmente insidiosa de) UB. Eso es lo que quise decir con ''lie to the linker''. Porque, al declarar sus variables de manera diferente en diferentes TU, eso es exactamente lo que hizo. Whoops!
Este es un seguimiento de esta pregunta .
Como se menciona en los comentarios a la respuesta:
Una variable en línea tiene la propiedad de que: tiene la misma dirección en cada unidad de traducción . [...] Por lo general, lo logró al definir la variable en un archivo cpp, pero con el especificador en línea simplemente puede declarar / definir sus variables en un archivo de encabezado y cada unidad de traducción que usa esta variable en línea usa exactamente el mismo objeto.
Además, a partir de la propia respuesta:
Si bien el idioma no garantiza (ni siquiera menciona) lo que sucede cuando utiliza esta nueva función en los límites de las bibliotecas compartidas, funciona en mi máquina.
En otros términos, no está claro si se garantiza que una variable en línea sea única a través de los límites cuando se trata de bibliotecas compartidas. Alguien demostró empíricamente que funciona en algunas plataformas, pero no es una respuesta adecuada y podría romper todo en otras plataformas.
¿Existe alguna garantía con respecto a la singularidad de una variable en línea cuando se usa a través de límites o es simplemente un detalle de implementación en el que no debo confiar?
Así es como interpreto el estándar. Según basic.link/1 :
Un programa consiste en una o más unidades de traducción unidas entre sí.
No dice nada sobre enlace estático ni enlace dinámico. Un programa es unidades de traducción unidas entre sí. No importa si la vinculación se realiza en dos pasos (primero cree una .dll / .so, y luego el vinculador dinámico vincula todas las librerías dinámicas + ejecutables juntas).
Por lo tanto, en mi interpretación, no importa si un programa está vinculado de forma dinámica o estática, la implementación debe comportarse de la misma manera: una variable estática de clase debe ser única (no importa si está en línea o no).
En Linux, esto es cierto.
En Windows, esto no funciona en todas las circunstancias, por lo que en mi interpretación, viola el estándar en estas circunstancias (si crea un archivo .dll separado, que contiene la variable estática, no en línea, y todos los demás archivos .dll y el exe se refiere a esta variable, funciona).
C ++ actualmente no tiene un concepto de bibliotecas compartidas. Por lo tanto, la forma inline
comporta inline
en las bibliotecas compartidas sería específica para la implementación y la plataforma.
El hecho de que basic.link/1 que " Un programa consta de una o más unidades de traducción conectadas entre sí" no significa que un programa vinculado entre sí con otro módulo ya vinculado debe comportarse de la misma manera.
Se han presentado muchas propuestas a lo largo de los años para rectificar la situación ( N1400 , N1418 , N1496 , N1976 , N2407 , N3347 , N4028 ), ninguna de las cuales despegó. Simplemente es difícil de implementar de una manera genérica, y C ++ generalmente trata de mantenerse fuera de los detalles de la implementación. Como GCC lo here :
Para los objetivos que no admiten COMDAT o símbolos débiles, la mayoría de las entidades con vínculos vagos se emiten como símbolos locales para evitar errores de definición duplicados en el vinculador. Sin embargo, esto no ocurre con las estadísticas locales en línea, ya que tener múltiples copias casi seguramente rompe cosas.
MSVC no expone ningún símbolo por defecto. Cualquier símbolo "externo" debe declararse explícitamente con una plataforma específica __declspec(dllexport)
. No se puede decir que Windows sea incompatible con C ++ debido a esto. Ninguna de las reglas de C ++ se violan aquí, porque no hay ninguna.