¿Por qué se utilizan espacios de nombres sin nombre y cuáles son sus beneficios?


Acabo de unirme a un nuevo proyecto de software C++ y estoy tratando de entender el diseño. El proyecto hace uso frecuente de espacios de nombres sin nombre. Por ejemplo, algo como esto puede ocurrir en un archivo de definición de clase:

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

¿Cuáles son las consideraciones de diseño que podrían hacer que uno use un espacio de nombres sin nombre? ¿Cuáles son las ventajas y desventajas?

Author: James McNellis, 2008-12-10

6 answers

(En lo siguiente, las cosas tachadas son cosas que ya no se aplican a C++11, pero sí se aplican a C++03. C++11 ya casi no hace diferencias (si las hay, son solo diferencias de abogados de lenguaje que no puedo recordar).).

Los espacios de nombres sin nombre son una utilidad para hacer un identificador efectivamente unidad de traducción local. Se comportan como si eligieras un nombre único por unidad de traducción para un espacio de nombres:

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

El paso adicional usar el cuerpo vacío es importante, por lo que ya puede referirse dentro del cuerpo del espacio de nombres a identificadores como ::name que están definidos en ese espacio de nombres, ya que la directiva using ya tuvo lugar.

Esto significa que puede tener funciones libres llamadas (por ejemplo) help que pueden existir en múltiples unidades de traducción, y no chocarán en el momento del enlace, ya que todas tienen un nombre único debido a su espacio de nombres único en el que se encuentran. El efecto es casi idéntico al uso del static palabra clave utilizada en C que puede poner en la declaración de identificadores. static usado de esa manera está obsoleto en C++, ya que los espacios de nombres sin nombre son una alternativa superior, pudiendo incluso hacer local una unidad de traducción de tipos.

namespace { int a1; }
static int a2;

Ambos a son locales de la unidad de traducción y no chocarán en el momento del enlace. Pero la diferencia es que el a1 en el espacio de nombres anónimo solo obtiene un nombre único. Todavía tiene enlace externo y puede exportarse a la tabla de símbolos del archivo objeto que se está creando. Esto se vuelve importante si desea usar su dirección como argumento de plantilla:

template<int * ptr> struct sample { };

// OK - a1 has external linkage
sample<&a1> s1; 
// NOT OK - translation unit locality is done by giving a2 internal linkage. 
sample<&a2> s2; 

Los parámetros de la plantilla deben tener un enlace externo, por lo que en este caso el identificador debe colocarse en un espacio de nombres anónimo.

Lea el excelente artículo en comeau-computing `¿Por qué se usa un espacio de nombres sin nombre en lugar de estático?.

 154
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-29 19:45:44

Tener algo en un espacio de nombres anónimo significa que es local a esta unidad de traducción (.archivo cpp y todas sus inclusiones) esto significa que si se define otro símbolo con el mismo nombre en otro lugar no habrá una violación de la Regla de una Definición (ODR).

Esto es lo mismo que la forma en C de tener una variable global estática o una función estática, pero también se puede usar para definiciones de clases (y debería usarse en lugar de static en C++).

Todos anónimos los espacios de nombres en el mismo archivo se tratan como el mismo espacio de nombres y todos los espacios de nombres anónimos en archivos diferentes son distintos. Un espacio de nombres anónimo es el equivalente de:

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;
 54
Author: Motti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-01 22:37:07

El ejemplo muestra que las personas en el proyecto al que te uniste no entienden los espacios de nombres anónimos:)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

Estos no necesitan estar en un espacio de nombres anónimo, ya que el objeto const ya tiene enlace estático y, por lo tanto, no puede entrar en conflicto con identificadores del mismo nombre en otra unidad de traducción.

    bool getState(userType*,otherUserType*);
}

Y esto es en realidad una pesimización: getState() tiene vinculación externa. Por lo general, es mejor preferir el enlace estático, ya que eso no contamina la tabla de símbolos. Es mejor escribir

static bool getState(/*...*/);

Aquí. Caí en la misma trampa (hay palabras en el estándar que sugieren que la estática de archivos está en desuso en favor de los espacios de nombres anónimos), pero trabajando en un gran proyecto de C++ como KDE, tienes muchas personas que vuelven la cabeza de nuevo:)

 12
Author: Marc Mutz - mmutz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-24 17:20:04

Además de las otras respuestas a esta pregunta, el uso de un espacio de nombres anónimo también puede mejorar el rendimiento. Como los símbolos dentro del espacio de nombres no necesitan ningún enlace externo, el compilador es más libre para realizar una optimización agresiva del código dentro del espacio de nombres. Por ejemplo, una función que se llama varias veces una vez en un bucle puede estar en línea sin ningún impacto en el tamaño del código.

Por ejemplo, en mi sistema el siguiente código toma alrededor del 70% del tiempo de ejecución si el se utiliza un espacio de nombres anónimo (x86 - 64 gcc-4.6.3 y-O2; tenga en cuenta que el código adicional en add_val hace que el compilador no quiera incluirlo dos veces).

#include <iostream>

namespace {
  double a;
  void b(double x)
  {
    a -= x;
  }
  void add_val(double x)
  {
    a += x;
    if(x==0.01) b(0);
    if(x==0.02) b(0.6);
    if(x==0.03) b(-0.1);
    if(x==0.04) b(0.4);
  }
}

int main()
{
  a = 0;
  for(int i=0; i<1000000000; ++i)
    {
      add_val(i*1e-10);
    }
  std::cout << a << '\n';
  return 0;
}
 11
Author: xioxox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-29 09:34:53

Un espacio de nombres anónimo crea las variables, funciones, clases, etc. incluidas. disponible solo dentro de ese archivo. En tu ejemplo es una forma de evitar variables globales. No hay diferencia de rendimiento en tiempo de ejecución o de compilación.

No Hay tanto una ventaja o desventaja, aparte de "¿quiero esta variable, función, clase, etc. ¿ser público o privado?"

 8
Author: Max Lybbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-10 21:19:28

Unnamed namespace limita el acceso de clase,variable,función y objetos al archivo en el que está definido. La funcionalidad de espacio de nombres sin nombre es similar a la palabra clave static en C/C++.
static la palabra clave limita el acceso de la variable global y la función al archivo en el que se definen.
Hay diferencia entre el espacio de nombres sin nombre y la palabra clave static debido a que el espacio de nombres sin nombre tiene ventaja sobre la estática. static la palabra clave se puede usar con variable, función y objetos, pero no con usuario clase definida.
Por ejemplo:

static int x;  // Correct 

Pero

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

Pero lo mismo puede ser posible con espacios de nombres sin nombre. Por ejemplo,

 namespace {
           class xyz {/*Body of class*/}
           static structure {/*Body of structure*/}
  } //Correct
 5
Author: Sachin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-10 00:21:40