¿Es #pragma una vez parte del estándar C ++ 11?

140

Tradicionalmente, la forma estándar y portátil de evitar múltiples inclusiones de encabezado en C ++ era / es usar el #ifndef - #define - #endifesquema de directivas precompilador también llamado esquema de macro-guardia (vea el fragmento de código a continuación).

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

Sin embargo, en la mayoría de las implementaciones / compiladores (vea la imagen a continuación), hay una alternativa más "elegante" que sirve para el mismo propósito que el esquema de macro-guardia llamado #pragma once. #pragma oncetiene varias ventajas en comparación con el esquema de macro-guardia, que incluye menos código, evitar conflictos de nombres y, a veces, una velocidad de compilación mejorada.

ingrese la descripción de la imagen aquí

Investigando un poco, me di cuenta de que aunque la #pragma oncedirectiva es compatible con casi todos los compiladores conocidos, existe una turbidez sobre si la #pragma oncedirectiva es parte del estándar C ++ 11 o no.

Preguntas:

  • ¿Podría alguien aclarar si la #pragma oncedirectiva es parte del estándar C ++ 11 o no?
  • Si no es parte del estándar C ++ 11, ¿hay planes para incluirlo en versiones posteriores (por ejemplo, C ++ 14 o posterior)?
  • También sería bueno si alguien pudiera profundizar en las ventajas / desventajas en el uso de cualquiera de las técnicas (es decir, macro-guardia versus #pragma once).
101010
fuente
9
Por cierto, el uso de guiones bajos dobles para los protectores de encabezado está prohibido por el estándar, que reserva para la implementación todos los símbolos que comienzan con guiones bajos dobles (además de otros).
Matteo Italia
9
El uso de un guión bajo seguido de una letra mayúscula también está prohibido. Segundo, ¿dónde está la turbidez? Acabo de ver el soporte del compilador, ¿no veo a nadie que afirme que es parte del estándar?
Yakk - Adam Nevraumont
1
Para el tercer punto, mire la pregunta relacionada: ¿Es #pragma una vez que un seguro incluye guardia? Se produjo una situación en la que los protectores de cabecera funcionan pero #pragma oncegeneralmente no.
user1942027
1
posible duplicado en que responde a esta pregunta sin mencionar C ++ 11.
Yakk - Adam Nevraumont
3
Bueno, no está codificado en ningún documento oficial, pero puede considerarlo como un estándar de facto .
Siyuan Ren

Respuestas:

107

#pragma onceNo es estándar. Es una extensión extendida (pero no universal), que se puede usar

  • si sus preocupaciones de portabilidad son limitadas, y
  • puede estar seguro de que todos sus archivos de inclusión siempre están en un disco local.

Se consideró para la estandarización, pero se rechazó porque no se puede implementar de manera confiable. (Los problemas se producen cuando tiene archivos accesibles a través de varios montajes remotos diferentes).

Es bastante fácil asegurarse de que no haya conflictos de protección de inclusión dentro de un solo desarrollo. Para las bibliotecas, que pueden ser utilizadas por muchos desarrollos diferentes, la solución obvia es generar muchos caracteres aleatorios para el protector de inclusión cuando lo cree. (Se puede configurar un buen editor para que haga esto por usted cada vez que abra un nuevo encabezado). Pero incluso sin esto, todavía no he encontrado ningún problema con conflictos entre bibliotecas.

James Kanze
fuente
11
No solo montajes remotos. Enlaces duros, enlaces blandos, construcciones secundarias (en Windows). Puede ponerse realmente desordenado.
Tonny
45
¿Por qué el compilador no puede usar las sumas de verificación SHA-1 o MD5 para identificar los archivos?
Sergey
29
Realmente no veo el punto de no poner algo en el estándar si todos los compiladores principales lo admiten. En realidad, hay cosas en el estándar mucho menos compatibles que esto. Además, parece bastante tonto quejarse de problemas de borde, cuando hablamos de archivos de inclusión, donde los conflictos de nombres de archivo ya son un gran problema. Hubiera sido bueno si esta demanda de una función 100% libre de problemas se hubiera aplicado al concepto de # encabezados incluidos en general.
TED
38
Si su código incluye algún archivo de diferentes ubicaciones a través de enlaces simbólicos o montajes extraños, entonces ya no es portátil. Por lo tanto, argumentar que pragma onceno se puede implementar de manera portátil algo que no es inherentemente portátil (y que ni siquiera se debe considerar) es otra tontería del mundo al revés de C ++.
doc
77
@JoseAntonioDuraOlmos Estoy de acuerdo en que los enlaces simbólicos son una característica del sistema operativo, que está fuera del alcance del lenguaje C ++. Por lo tanto, surge la pregunta de por qué el comité de C ++ debería considerar algo que está fuera del alcance del lenguaje. Intentar garantizar algo que no es su responsabilidad no tiene ningún sentido IMO. DOS ha admitido solo 8 + 3 caracteres por nombre de archivo, sin embargo, nadie argumentó que #includetiene que eliminarse, ya que se puede usar indebidamente la directiva. #pragma onceno restringe la portabilidad de ninguna manera, siempre que no explote los enlaces simbólicos para romper la compilación.
doc
32

La Sección § 16.6 de la Norma ( borrador N3936 ) describe las #pragmadirectivas como:

Una directiva de preprocesamiento del formulario

# pragma pp-tokensopt new-line

hace que la implementación se comporte de una manera definida por la implementación. El comportamiento puede hacer que la traducción falle o que el traductor o el programa resultante se comporten de manera no conforme. Cualquier pragma que no sea reconocido por la implementación se ignora.

Básicamente #pragma oncees una instancia específica de implementación de una #pragmadirectiva, y no, no es estándar. Todavía.

A menudo es ampliamente compatible con la mayoría de los "compiladores principales", incluidos GCC y Clang y, por lo tanto, a veces se recomienda evitar la placa de protección de inclusión.

Zapato
fuente
10
Tenga en cuenta que puede ambos #pragmay #defineencabezado-guardia.
Yakk - Adam Nevraumont
18
"Cualquier pragma que no sea reconocido por la implementación es ignorado" . ¿Significa que el mensaje: Advertencia: la directiva pragma no reconocida no es conforme?
rodrigo
66
"y, por lo tanto, es la forma recomendada de evitar repetitivos de incluir-guardias" - una declaración muy audaz. Es una forma no estándar, y los beneficios de usarlo son pocos y apenas han sido relevantes en mi experiencia, así que tuve que quitar mi +1.
Alex
19
@Yakk: Si alguien escribe #defineencabezado, él / ella NO tiene razón para escribir #pragma oncetambién.
Nawaz
55
@Nawaz Un compilador puede mantener un caché de cada archivo (por ruta) que ha sido #pragma onced, y en el caso de que sea #included nuevamente puede omitir el #include(ni siquiera abrir el archivo). gcc hace lo mismo con los protectores de encabezado, pero es muy, muy frágil. El #pragmauno es fácil de hacer, el protector de cabecera es difícil.
Yakk - Adam Nevraumont