Pregunta

Una característica de C ++ es la capacidad de crear espacios de nombres sin nombre (anónimos), como por ejemplo:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

Usted 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 cualquier elemento desde dentro. Pero estos espacios de nombre sin nombre son accesibles dentro del archivo en el que se crearon, como si tuvieras una cláusula de uso implícita para ellos.

Mi pregunta es, ¿por qué o cuándo sería preferible utilizar funciones estáticas? ¿O son esencialmente dos formas de hacer exactamente lo mismo?

¿Fue útil?

Solución

El estándar de C ++ se lee en la sección 7.3.1.1 espacios de nombres sin nombre, párrafo 2:

  

El uso de la palabra clave estática es   en desuso al declarar objetos en una   ámbito de espacio de nombres, el espacio de nombres sin nombre   Proporciona una alternativa superior.   

La estática solo se aplica a los nombres de objetos, funciones y uniones anónimas, no a las 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 obtener más información, consulte esta SO pregunta.

Los espacios de nombre sin nombre aún tienen la ventaja de permitirle definir tipos de unidad de traducción locales. Consulte esta pregunta SO para más detalles.

El crédito va a Mike Percy por comunicarme esto.

Otros consejos

Poner métodos en un espacio de nombres anónimo te impide violar accidentalmente la One Definition Rule , permitiéndote nunca se preocupe por nombrar a sus métodos de ayuda de la misma manera que a cualquier otro método que pueda vincular.

Y, como señala luke, los espacios de nombres anónimos son preferidos por el estándar sobre los miembros estáticos.

Hay un caso de borde donde la estática tiene un efecto sorprendente (al menos lo fue para mí). El estándar C ++ 03 establece en 14.6.4.2/1:

  

Para una llamada de función que depende de un parámetro de plantilla, si el nombre de la función es un no calificado-id pero no un template-id , las funciones candidatas se encuentran usando las reglas de búsqueda habituales (3.4.1, 3.4.2) excepto que:

     
      
  • Para la parte de la búsqueda que utiliza la búsqueda de nombre no calificado (3.4.1), solo se encuentran las declaraciones de funciones con vínculos externos desde el contexto de definición de la plantilla.
  •   
  • Para la parte de la búsqueda que utiliza espacios de nombres asociados (3.4.2), solo se encuentran las declaraciones de funciones con vínculos externos que se encuentran en el contexto de definición de la plantilla o en el contexto de creación de instancias de la plantilla.
  •   
     

...

El código de abajo llamará a foo (void *) y no a foo (S const & amp;) como podría esperarse.

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

En sí mismo, esto probablemente no sea tan importante, pero lo resalta para un compilador de C ++ totalmente compatible (es decir, uno con soporte para export ) la palabra clave static seguirá teniendo la funcionalidad que no está disponible de ninguna otra manera.

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

La única forma de asegurarse de que la función en nuestro espacio de nombres sin nombre no se encuentre en las plantillas que usan ADL es hacer que static .

Actualización para C ++ moderno

A partir de C ++ '11, los miembros de un espacio de nombres sin nombre tienen vínculos internos implícitamente (3.5 / 4):

  

Un espacio de nombres sin nombre o un espacio de nombres declarado directa o indirectamente dentro de un espacio de nombres sin nombre tiene un enlace interno.

Pero al mismo tiempo, se actualizó 14.6.4.2/1 para eliminar la mención del enlace (tomado de C ++ '14):

  

Para una llamada de función en la que la expresión postfix es un nombre dependiente, las funciones candidatas se encuentran usando   las reglas de búsqueda habituales (3.4.1, 3.4.2) excepto que:

     
      
  • Para la parte de la búsqueda que utiliza la búsqueda de nombre no calificado (3.4.1), solo se encuentran las declaraciones de funciones del contexto de definición de la plantilla.

  •   
  • Para la parte de la búsqueda que utiliza espacios de nombres asociados (3.4.2), solo se encuentran las declaraciones de funciones encontradas en el contexto de definición de la plantilla o en el contexto de creación de instancias de la plantilla.

  •   

El resultado es que ya no existe esta diferencia particular entre los miembros del espacio de nombres estáticos y sin nombre.

Recientemente comencé a reemplazar palabras clave estáticas con espacios de nombres anónimos en mi código, pero inmediatamente tuve un problema en el que las variables en el espacio de nombres ya no estaban disponibles para 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 de 'módulo', donde le di el nombre de mi archivo cpp.

Por ejemplo, en mi archivo XmlUtil.cpp, defino un espacio de nombres XmlUtil_I {...} para todas mis variables y funciones del módulo. De esa manera puedo aplicar la calificación XmlUtil_I :: en el depurador para acceder a las variables. En este caso, el '_I' lo distingue de un espacio de nombres público como XmlUtil que tal vez quiera usar en otro lugar.

Supongo que una desventaja potencial de este enfoque en comparación con uno realmente anónimo es que alguien podría violar el alcance estático deseado utilizando el calificador de espacio de nombres en otros módulos. Sin embargo, no sé si esa es una preocupación importante.

El uso de la palabra clave estática para ese propósito está obsoleto 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.

Por experiencia, solo señalaré que si bien es la forma en C ++ de colocar 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 funciona bien al 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 lo marcará como un error. El error no es lo que me preocupa, es lo que podría hacer cuando lo acepta . Por lo tanto, hasta que seamos modernos en general, seguimos utilizando funciones estáticas (generalmente de clase) en las que preferiríamos el espacio de nombres anónimo.

Además, si se usa una palabra clave estática en una variable como este ejemplo:

namespace {
   static int flag;
}

No se vería en el archivo de mapeo

Habiendo aprendido de esta función solo ahora mientras leo tu pregunta, solo puedo especular. Esto parece proporcionar varias ventajas sobre una variable estática a nivel de archivo:

  • Los espacios de nombres anónimos se pueden anidar entre sí, proporcionando múltiples niveles de protección de los que los símbolos no pueden escapar.
  • Se podrían colocar varios espacios de nombres anónimos en el mismo archivo de origen, creando en efecto diferentes ámbitos de nivel estático dentro del mismo archivo.

Me gustaría saber si alguien ha utilizado espacios de nombres anónimos en código real.

Se puede ver una diferencia específica del compilador entre los espacios de nombres anónimos y las funciones estáticas al compilar el siguiente código.

#include <iostream>

namespace
{
    void unreferenced()
    {
        std::cout << "Unreferenced";
    }

    void referenced()
    {
        std::cout << "Referenced";
    }
}

static void static_unreferenced()
{
    std::cout << "Unreferenced";
}

static void static_referenced()
{
    std::cout << "Referenced";
}

int main()
{
    referenced();
    static_referenced();
    return 0;
}

Compilando este código con VS 2017 (especificando el indicador de advertencia de nivel 4 / W4 para habilitar 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 producirá Una advertencia para la función estática no utilizada. gcc 4.9 y versiones posteriores, así como el lenguaje lógico 3.3 y versiones posteriores, generarán advertencias para la función sin referencia 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

Personalmente prefiero las funciones estáticas a los espacios de nombres sin nombre por las siguientes razones:

  • es obvio y claro, solo desde la definición de la función, que es privado a 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 siguen siendo 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 obviamente son solo C ++. los espacios de nombres sin nombre también agregan un nivel adicional si la sangría y no me gusta eso :)

Entonces, me alegra ver que el uso de estática para las funciones ya no está en desuso .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top