Una característica de C ++ es la capacidad de crear espacios de nombres sin nombre (anónimos), de esta manera:
namespace {
int cannotAccessOutsideThisFile() { ... }
} // namespace
Pensaría que tal característica sería inútil, ya que no puede especificar el nombre del espacio de nombres, es imposible acceder a nada desde fuera. Pero estos espacios de nombres sin nombre son accesibles dentro del archivo en el que se crean, como si tuviera una cláusula de uso implícita.
Mi pregunta es, ¿por qué o cuándo sería preferible usar funciones estáticas? ¿O son esencialmente dos formas de hacer exactamente lo mismo?
c++
namespaces
Head Geek
fuente
fuente
static
en este contexto no estaba en desuso ; Aunque el espacio de nombres sin nombre es una alternativa superior astatic
, hay casos en los que falla cuando sestatic
trata del rescate .Respuestas:
El estándar C ++ se lee en la sección 7.3.1.1 Espacios de nombres sin nombre, párrafo 2:Estático solo se aplica a nombres de objetos, funciones y uniones anónimas, no a declaraciones de tipo.
Editar:
La decisión de desaprobar este uso de la palabra clave estática (afectar la visibilidad de una declaración de variable en una unidad de traducción) se ha revertido ( ref ). En este caso, el uso de un espacio de nombres estático o sin nombre vuelve a ser esencialmente dos formas de hacer exactamente lo mismo. Para más discusión por favor vea esta pregunta SO.
Los espacios de nombres sin nombre aún tienen la ventaja de permitirle definir tipos locales de unidades de traducción. Consulte esta pregunta SO para obtener más detalles.
El crédito es para Mike Percy por llamar mi atención sobre esto.
fuente
namespace
s sin nombre tienen implícitamente un enlace interno, por lo que no debería haber ninguna diferencia. Cualquier problema que pudiera haber surgido anteriormente debido a una redacción deficiente se resolvió al hacer esto un requisito en C ++ 11.Poner los métodos en un espacio de nombres anónimo le impide violar accidentalmente la Regla de una definición , lo que le permite no preocuparse por nombrar sus métodos auxiliares de la misma manera que con cualquier otro método que pueda vincular.
Y, como señaló Luke, los espacios de nombres anónimos son preferidos por el estándar sobre los miembros estáticos.
fuente
Hay un caso extremo en el que la estática tiene un efecto sorprendente (al menos para mí). El estándar C ++ 03 establece en 14.6.4.2/1:
El código a continuación llamará
foo(void*)
y nofoo(S const &)
como es de esperar.En sí mismo, esto probablemente no sea un gran problema, pero destaca que para un compilador de C ++ totalmente compatible (es decir, uno con soporte para
export
) lastatic
palabra clave seguirá teniendo una funcionalidad que no está disponible de ninguna otra manera.La única forma de garantizar que la función en nuestro espacio de nombres sin nombre no se encuentre en las plantillas que usan ADL es hacerlo
static
.Actualización para Modern C ++
A partir de C ++ '11, los miembros de un espacio de nombres sin nombre tienen vinculación interna implícitamente (3.5 / 4):
Pero al mismo tiempo, se actualizó 14.6.4.2/1 para eliminar la mención de vinculación (tomado de C ++ '14):
El resultado es que esta diferencia particular entre miembros de espacio de nombres estáticos y sin nombre ya no existe.
fuente
NS::S
trabajar, ¿noS
necesita no estar adentronamespace {}
?Recientemente comencé a reemplazar palabras clave estáticas con espacios de nombres anónimos en mi código, pero inmediatamente me encontré con un problema en el que las variables en el espacio de nombres ya no estaban disponibles para su inspección en mi depurador. Estaba usando VC60, así que no sé si eso no es un problema con otros depuradores. Mi solución fue definir un espacio de nombres 'módulo', donde le di el nombre de mi archivo cpp.
Por ejemplo, en mi archivo XmlUtil.cpp, defino un espacio
XmlUtil_I { ... }
de nombres para todas las variables y funciones de mi módulo. De esa manera puedo aplicar laXmlUtil_I::
calificación en el depurador para acceder a las variables. En este caso, lo_I
distingue de un espacio de nombres público como elXmlUtil
que tal vez quiera usar en otro lugar.Supongo que una desventaja potencial de este enfoque en comparación con uno verdaderamente anónimo es que alguien podría violar el alcance estático deseado al usar el calificador de espacio de nombres en otros módulos. Sin embargo, no sé si eso es una preocupación importante.
fuente
#if DEBUG namespace BlahBlah_private { #else namespace { #endif
, por lo que el "espacio de nombres del módulo" solo está presente en las compilaciones de depuración y el espacio de nombres anónimo verdadero se usa de lo contrario. Sería bueno si los depuradores dieran una buena manera de manejar esto. Doxygen también se confunde.El uso de la palabra clave estática para ese fin está en desuso por el estándar C ++ 98. El problema con la estática es que no se aplica a la definición de tipo. También es una palabra clave sobrecargada utilizada de diferentes maneras en diferentes contextos, por lo que los espacios de nombres sin nombre simplifican un poco las cosas.
fuente
Por experiencia, solo notaré que si bien es la forma en C ++ de poner funciones anteriormente estáticas en el espacio de nombres anónimo, los compiladores más antiguos a veces pueden tener problemas con esto. Actualmente trabajo con algunos compiladores para nuestras plataformas de destino, y el compilador de Linux más moderno está bien para colocar funciones en el espacio de nombres anónimo.
Pero un compilador más antiguo que se ejecuta en Solaris, con el que estamos casados hasta una versión futura no especificada, a veces lo aceptará, y otras veces lo marcará como un error. El error no es lo que me preocupa, es lo que podría estar haciendo cuando lo acepta . Entonces, hasta que seamos modernos en todos los ámbitos, todavía estamos usando funciones estáticas (generalmente de ámbito de clase) donde preferiríamos el espacio de nombres anónimo.
fuente
Además, si se usa una palabra clave estática en una variable como este ejemplo:
No se vería en el archivo de mapeo
fuente
Se puede ver una diferencia específica del compilador entre espacios de nombres anónimos y funciones estáticas compilando el siguiente código.
Compilar este código con VS 2017 (especificando el indicador de advertencia de nivel 4 / W4 para habilitar el aviso C4505: se ha eliminado la función local sin referencia ) y gcc 4.9 con la función -Wunused-function o -Wall indica que VS 2017 solo generará una advertencia para La función estática no utilizada. gcc 4.9 y superior, así como clang 3.3 y superior, generarán advertencias para la función no referenciada en el espacio de nombres y también una advertencia para la función estática no utilizada.
Demostración en vivo de gcc 4.9 y MSVC 2017
fuente
Personalmente, prefiero las funciones estáticas a los espacios de nombres sin nombre por los siguientes motivos:
Es obvio y claro desde la definición de la función solo que es privado para la unidad de traducción donde se compila. Con el espacio de nombres sin nombre, es posible que deba desplazarse y buscar para ver si una función está en un espacio de nombres.
Las funciones en los espacios de nombres pueden ser tratadas como externas por algunos compiladores (más antiguos). En VS2017 todavía son externos. Por esta razón, incluso si una función está en un espacio de nombres sin nombre, es posible que desee marcarlos como estáticos.
Las funciones estáticas se comportan de manera muy similar en C o C ++, mientras que los espacios de nombres sin nombre son obviamente solo C ++. los espacios de nombres sin nombre también agregan un nivel adicional en la sangría y eso no me gusta :)
Entonces, me alegra ver que el uso de static para funciones ya no está en desuso .
fuente
static
palabra clave realmente aplica el enlace local a una función. Además, ¿seguramente solo un loco loco realmente agregaría sangría para espacios de nombres?Al haber aprendido esta característica hace un momento mientras leía su pregunta, solo puedo especular. Esto parece proporcionar varias ventajas sobre una variable estática a nivel de archivo:
Me interesaría saber si alguien ha usado espacios de nombres anónimos en código real.
fuente
La diferencia es el nombre del identificador destrozado (
_ZN12_GLOBAL__N_11bE
vs_ZL1b
, que realmente no importa, pero ambos se ensamblan en símbolos locales en la tabla de símbolos (ausencia de.global
directiva asm).En cuanto a un espacio de nombres anónimo anidado:
Todos los espacios de nombres anónimos de primer nivel en la unidad de traducción se combinan entre sí. Todos los espacios de nombres anónimos de segundo nivel en la unidad de traducción se combinan entre sí.
También puede tener un espacio de nombres anidado (en línea) en un espacio de nombres anónimo
También puede tener espacios de nombres en línea anónimos, pero por lo que puedo decir,
inline
en un espacio de nombres anónimo tiene un efecto 0_ZL1b
:_Z
significa que este es un identificador destrozado.L
significa que es un símbolo local a través destatic
.1
es la longitud del identificadorb
y luego el identificadorb
_ZN12_GLOBAL__N_11aE
_Z
significa que este es un identificador destrozado.N
significa que este es un espacio de nombres12
es la longitud del nombre de espacio de nombres anónimo_GLOBAL__N_1
, luego el nombre de espacio de nombres anónimo_GLOBAL__N_1
, luego1
es la longitud del identificadora
,a
es el identificadora
yE
cierra el identificador que reside en un espacio de nombres._ZN12_GLOBAL__N_11A1aE
es el mismo que el anterior, excepto que hay otro nivel de espacio de nombres en él1A
fuente