Parece haber diferentes puntos de vista sobre el uso de 'usar' con respecto al espacio de nombres estándar.
Algunos dicen usar ' using namespace std
', otros dicen que no, sino prefijar las funciones estándar que se usarán con ' std::
', mientras que otros dicen que use algo como esto:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
para todas las funciones estándar que se van a utilizar.
¿Cuáles son los pros y los contras de cada uno?
c++
namespaces
paoloricardo
fuente
fuente
Respuestas:
La mayoría de los usuarios de C ++ están muy contentos de leer
std::string
,std::vector
etc. De hecho, ver un archivo sinvector
formato me hace preguntarme si este es elstd::vector
definido por el usuario o uno diferentevector
.Siempre estoy en contra de consumir
using namespace std;
. Importa todo tipo de nombres en el espacio de nombres global y puede causar todo tipo de ambigüedades no obvias.A continuación, se muestran algunos identificadores comunes que se encuentran en el
std
espacio de nombres: contar, ordenar, buscar, igualar, invertir. Tener una variable local llamadacount
significa queusing namespace std
no le permitirá usar encount
lugar destd::count
.El ejemplo clásico de un conflicto de nombres no deseado es algo como el siguiente. Imagina que eres un principiante y no sabes nada
std::count
. Imagina que estás usando algo más<algorithm>
o ha sido introducido por un encabezado aparentemente no relacionado.El error suele ser largo y poco amigable porque
std::count
es una plantilla con algunos tipos anidados largos.Sin embargo, esto está bien, porque
std::count
entra en el espacio de nombres global y el recuento de funciones lo oculta.Quizás sorprendentemente, esto está bien. Los identificadores importados en un ámbito declarativo aparecen en el espacio de nombres común que incluye tanto dónde se definen como dónde se importan. En otras palabras,
std::count
es visible comocount
en el espacio de nombres global, pero solo dentroincrement
.Y por razones similares,
count
aquí es ambiguo.using namespace std
no causastd::count
, esconde el exteriorcount
como podría esperarse. Lausing namespace
regla significa questd::count
parece (en laincrement
función) como si estuviera declarada en el ámbito global, es decir, en el mismo ámbitoint count = 0;
y, por tanto, provocando la ambigüedad.fuente
using std::xxx;
. No contamina el espacio de nombres, la escritura del código será más corta y creo quecopy
es mucho más real questd::copy
.Excluyendo los conceptos básicos (tener que agregar std :: enfrente de todos los objetos / funciones stl y menos posibilidades de conflicto si no tiene 'using namespace std')
También vale la pena señalar que nunca debe poner
En un archivo de encabezado, ya que puede propagarse a todos los archivos que incluyen ese archivo de encabezado, incluso si no quieren usar ese espacio de nombres.
En algunos casos, es muy beneficioso usar cosas como
Como si hubiera una versión especializada de swap, el compilador la usará, de lo contrario recurrirá a ella
std::swap
.Si llama
std::swap
, siempre usa la versión básica, que no llamará a la versión optimizada (si existe).fuente
using std::swap
(que es lo único que uso).u n s
puede propagar. Solo para tener en cuenta que también puede abrirse camino en encabezados construidos correctamente: solo deben incluirse después de un encabezado falso.swap
omove
(ohash
,less
etc.), debería poner esa especialización denamespace std
todos modos. Por ejemplo:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
Primero, algo de terminología:
using std::vector;
using namespace std;
Creo que el uso de directivas de uso está bien, siempre que no se utilicen en el ámbito global en un archivo de encabezado. Así que teniendo
en su archivo .cpp no es realmente un problema, y si resulta serlo, está completamente bajo su control (e incluso puede tener un alcance en bloques particulares si lo desea). No veo ninguna razón en particular para saturar el código con una gran cantidad de
std::
calificadores, simplemente se convierte en un montón de ruido visual. Sin embargo, si no está usando un montón de nombres delstd
espacio de nombres en su código, tampoco veo ningún problema en omitir la directiva. Es una tautología: si la directiva no es necesaria, no es necesario utilizarla.De manera similar, si puede arreglárselas con algunas declaraciones de uso (en lugar de directivas de uso ) para tipos específicos en el
std
espacio de nombres, entonces no hay razón por la que no deba traer solo esos nombres específicos al espacio de nombres actual. De la misma manera, creo que sería una locura y una molestia contable tener 25 o 30 declaraciones de uso cuando una sola directiva de uso funcionaría igual de bien.También es bueno tener en cuenta que hay ocasiones en las que debe usar una declaración using. Consulte el "Elemento 25: Considere la posibilidad de admitir un intercambio sin lanzamiento" de Scott Meyers de Effective C ++, tercera edición. Para que una función genérica con plantilla use el 'mejor' método de intercambio para un tipo parametrizado, debe hacer uso de una declaración de uso y una búsqueda dependiente de argumentos (también conocida como búsqueda de ADL o Koenig):
Creo que deberíamos mirar los modismos comunes para varios idiomas que hacen un uso significativo de los espacios de nombres. Por ejemplo, Java y C # usan espacios de nombres en gran medida (posiblemente más que C ++). La forma más común en que los nombres dentro de los espacios de nombres se usan en esos lenguajes es llevándolos al alcance actual en masa con el equivalente de una directiva using. Esto no causa problemas generalizados, y las pocas veces que se trata de un problema se maneja en forma de "excepción" tratando con los nombres en cuestión a través de nombres completamente calificados o mediante alias, como se puede hacer en C ++.
Herb Sutter y Andrei Alexandrescu tienen esto que decir en "Ítem 59: No escriba usos de espacios de nombres en un archivo de encabezado o antes de un #include" de su libro, Estándares de codificación C ++: 101 reglas, pautas y mejores prácticas:
Stroupstrup a menudo se cita diciendo, "No contaminen el espacio de nombres global", en "El lenguaje de programación C ++, tercera edición". De hecho dice eso (C.14 [15]), pero se refiere al capítulo C.10.1 donde dice:
¿Y cómo se tiene la misma ventaja que un 'usuario perezoso de nombres globales'? Aprovechando la directiva using, que hace que los nombres de un espacio de nombres estén disponibles para el ámbito actual de forma segura .
Tenga en cuenta que hay una distinción: los nombres en el
std
espacio de nombres puestos a disposición de un ámbito con el uso adecuado de una directiva de uso (colocando la directiva después de#includes
) no contaminan el espacio de nombres global. Es simplemente hacer que esos nombres estén disponibles fácilmente y con una protección continua contra los enfrentamientos.fuente
std::
calificadores no abarroten el código; hay otras formas de evitar eso (las declaraciones de uso o las definiciones de tipo suelen hacer el truco).using namespace std;
directiva " " no te impide declarar tu identificador naturallist
", es solo que si lo haces, no puedes uso más prolongadostd::list
sin calificarlo. Eso no es diferente a si no hay "using namespace std;
" directiva. ¿O me estoy perdiendo algo?Nunca use el uso del espacio de nombres en el ámbito global en un archivo de encabezado. Eso puede dar lugar a un conflicto y la persona a cargo del archivo donde aparece el conflicto no tiene control sobre la causa.
En el archivo de implementación, las opciones están mucho peor cortadas.
Poner un espacio de nombres using std trae todos los símbolos de esos espacios de nombres. Esto puede ser problemático ya que casi nadie conoce todos los símbolos que están allí (por lo que es imposible aplicar una política de no conflicto en la práctica) sin hablar de los símbolos que se agregarán. Y el estándar C ++ permite que un encabezado agregue símbolos de otros encabezados (el C no permite eso). Todavía puede funcionar bien en la práctica para simplificar la escritura en caso controlado. Y si ocurre un error, se detecta en el archivo que tiene el problema.
Poner usando std :: nombre; tiene la ventaja de la sencillez de escritura sin el riesgo de importar símbolos desconocidos. El costo es que debe importar explícitamente todos los símbolos deseados.
La calificación explícita agrega un poco de desorden, pero creo que es la práctica menos problemática.
En mi proyecto, uso una calificación explícita para todos los nombres, acepto usar std :: name, lucho contra usar el espacio de nombres std (tenemos un intérprete lisp que tiene su propio tipo de lista y, por lo tanto, el conflicto es algo seguro).
Para otros espacios de nombres, también debe tener en cuenta las convenciones de nomenclatura utilizadas. Sé de un proyecto que usa espacio de nombres (para control de versiones) y prefijo en nombres. Hacer un
using namespace X
then es casi sin riesgo y no hacerlo conduce a un código de aspecto estúpidoPrefixNS::pfxMyFunction(...)
.Hay algunos casos en los que desea importar los símbolos. std :: swap es el caso más común: importa std :: swap y luego usa swap unqualified. La búsqueda dependiente del argumento encontrará un intercambio adecuado en el espacio de nombres del tipo, si hay uno, y volverá a la plantilla estándar si no hay ninguno.
Editar:
En los comentarios, Michael Burr se pregunta si los conflictos ocurren en el mundo real. Aquí hay un ejemplo real en vivo. Tenemos un idioma de extensión con un dialecto ceceo. Nuestro intérprete tiene un archivo de inclusión, lisp.h que contiene
Tuvimos que integrar y adaptar un código (que llamaré "motor") que se veía así:
Así que modificamos así:
Bueno. Todo funciona. Algunos meses más tarde, "module.h" fue modificado para incluir "list.h". Pasaron las pruebas. "módulo" no se había modificado de una manera que afectara su ABI, por lo que la biblioteca "motor" podría usarse sin volver a compilar sus usuarios. Las pruebas de integración estuvieron bien. Nuevo "módulo" publicado. La siguiente compilación del motor se rompió cuando su código no se ha modificado.
fuente
Si no tiene riesgo de conflictos de nombres en su código con std y otras bibliotecas, puede usar:
Pero si desea saber con precisión la dependencia de su código para la documentación o existe el riesgo de conflictos de nombres, utilice el otro método:
La tercera solución, no use estas soluciones y escriba std :: antes de cada uso en el código le brinda más seguridad, pero tal vez un poco de peso en el código ...
fuente
Ambos
y
agregue algunos símbolos (uno o muchos) al espacio de nombres global. Y agregar símbolos al espacio de nombres global es algo que nunca debe hacer en los archivos de encabezado. No tienes control sobre quién incluirá tu encabezado, hay muchos encabezados que incluyen otros encabezados (y encabezados que incluyen encabezados que incluyen encabezados, etc.).
En los archivos de implementación (.cpp), depende de usted (solo recuerde hacerlo después de todas las directivas #include). Puede romper solo el código en este archivo específico, por lo que es más fácil de administrar y descubrir el motivo del conflicto de nombres. Si prefiere usar std :: (o cualquier otro prefijo, puede haber muchos espacios de nombres en su proyecto) antes de los identificadores, está bien. Si desea agregar identificadores que usa al espacio de nombres global, está bien. Si desea traer todo el espacio de nombres en su cabeza :-), depende de usted. Si bien los efectos se limitan a una sola unidad de compilación, es aceptable.
fuente
Para mí, prefiero usar
::
cuando sea posible.Odio escribir:
Con suerte, con C ++ 0x escribiría esto:
Si el espacio de nombres es muy extenso,
fuente
++i
, noi++
porque, si está definido, cree una copia temporal innecesaria del iterador.Nunca debe estar
using namespace std
en el ámbito del espacio de nombres en un encabezado. Además, supongo que la mayoría de los programadores se preguntarán cuándo venvector
ostring
nostd::
, así que creo que nousing namespace std
es mejor. Por lo tanto, defiendo que nunca lo seausing namespace std
.Si cree que debe hacerlo, agregue declaraciones locales usando como
using std::vector
. Pero pregúntese: ¿Qué valor tiene esto? Una línea de código se escribe una vez (quizás dos), pero se lee diez, cien o mil veces. El esfuerzo de mecanografía ahorrado al agregar una declaración o directiva using es marginal en comparación con el esfuerzo de leer el código.Con eso en mente, en un proyecto de hace diez años decidimos calificar explícitamente todos los identificadores con sus nombres completos de espacio de nombres. Lo que parecía incómodo al principio se convirtió en rutina en dos semanas. Ahora, en todos los proyectos de toda esa empresa ya nadie usa directivas o declaraciones de uso. (Con una excepción, ver más abajo). Mirando el código (varios MLoC) después de diez años, siento que tomamos la decisión correcta.
He descubierto que, por lo general, quienes se oponen a la prohibición no
using
lo han probado para un proyecto. Aquellos que lo han intentado, a menudo lo encuentran mejor que usar directivas / declaraciones después de muy poco tiempo.Nota: La única excepción es
using std::swap
qué es necesario (especialmente en código genérico) para recoger sobrecargasswap()
que no se pueden poner en elstd
espacio de nombres (porque no se nos permite poner sobrecargas destd
funciones en este espacio de nombres).fuente
std
, pero no sobrecargarlas. Perdón por ese pedo mental. Corregiré la publicación.using namespace
directiva fuera hacer mecanografía ; más bien, fue para facilitar la lectura , porque, como usted dice, ese código tendrá que leerse decenas, cientos o miles de veces. Y para algunas personas, se lee mucho más fácil y con menosstd::
desorden. Pero eso probablemente se reduce a la capacidad perceptiva personal; algunas personas lo filtranstd::
o incluso lo necesitan como guía (como serifas), otras lo apilan y se sienten como en un camino lleno de baches.Los espacios de nombres mantienen el código contenido para evitar la confusión y la contaminación de las firmas de funciones.
Aquí hay una demostración completa y documentada del uso adecuado del espacio de nombres :
Salida:
fuente
using namespace std
importa el contenido delstd
espacio de nombres en el actual. Por tanto, la ventaja es que no tendrá que escribirstd::
delante de todas las funciones de ese espacio de nombres. Sin embargo, puede suceder que tenga diferentes espacios de nombres que tengan funciones con el mismo nombre. Por lo tanto, es posible que no termine llamando al que desea.Especificar manualmente en cuáles desea importar
std
evita que eso suceda, pero puede resultar en una larga lista de uso al principio de su archivo, que algunos desarrolladores encontrarán desagradable;)!Personalmente, prefiero especificar el espacio de nombres cada vez que uso use una función, excepto cuando el espacio de nombres es demasiado largo, en cuyo caso pongo algo de uso al principio del archivo.
EDITAR: como se señaló en otra respuesta, nunca debe colocar un
using namespace
en un archivo de encabezado, ya que se propagará a todos los archivos, incluido este encabezado y, por lo tanto, puede producir un comportamiento no deseado.EDIT2: corrigió mi respuesta, gracias al comentario de Charles.
fuente
using namespace std;
importa el contenido delstd
espacio nombres en el espacio de nombres global. No cambia el espacio de nombres predeterminado. Definir algo en el espacio de nombres global después deusing namespace std
no lo colocará mágicamente en elstd
espacio de nombres.Al igual que en Java, donde puede usar puede incluir java.util. * O simplemente seleccionar cada clase individualmente, depende del estilo. Tenga en cuenta que no desea uno
using namespace std
al comienzo de su archivo / alcance amplio porque contaminará el espacio de nombres y posiblemente tendrá conflictos, anulando el punto de los espacios de nombres. Pero si tiene una función que usa mucho STL, desordena el código para tener una mezcla de sintaxis de prefijos en su lógica y probablemente debería considerar usarusing namespace std
(cuando usa una variedad de clases) ousing
s individuales (cuando usa algunas clases a menudo).fuente
Esta discusión estará viva siempre que el IDE con el que trabaja no sea lo suficientemente flexible para mostrar u ocultar la información exacta que necesita.
Esto se debe a que el aspecto que desea que tenga su código depende de la tarea en cuestión.
Al crear mi código fuente, prefiero ver exactamente qué clase estoy usando: ¿es
std::string
o laBuzFlox::Obs::string
clase?Al diseñar el flujo de control, ni siquiera me interesan los tipos de variables, pero quiero centrarme en
if
las ywhile
las ycontinue
las.Así que este es mi consejo:
Dependiendo de la audiencia de su código y el poder de sus herramientas, elija la forma que se lea más fácilmente o que proporcione más información.
fuente
Hay varias formas de solucionarlo.
Primero: use como lo hizo.
Segundo: hazlo
namespace S = std;
, reduciendo 2 caracteres.Tercero: uso
static
.Cuarto: no use nombres que
std
use.fuente
La única razón para dejar std :: es que, en teoría, podría volver a implementar todas las funciones STL usted mismo. Entonces sus funciones podrían cambiarse de usar std :: vector a my :: vector sin cambiar el código.
fuente
Por que no por ejemplo
en lugar de los difíciles de manejar
Lo encuentro mucho más legible y es mi estándar de codificación.
Incluso puede usarlo para incluir información semántica para el lector. Por ejemplo, considere los prototipos de funciones
cuales el valor de retorno?
Que tal en cambio
fuente