usar una namespace funciones estandar espacios espacio escribir ejemplos con como clase borland c++ namespaces

c++ - una - Usando el espacio de nombres estándar



public class en c++ (15)

Cuáles son los pros y los contras de cada uno

La única razón para dejar el std :: es que, en teoría, podría volver a implementar todas las funciones de STL. Entonces sus funciones podrían cambiarse de std :: vector a my :: vector sin cambiar el código.

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 no, pero prefieren prefijar las funciones estándar que se usarán con '' std:: '', mientras que otros dicen que usan 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 utilizarán.

¿Cuáles son los pros y los contras de cada uno? |


Al igual que en Java, donde puedes usar cualquiera, puede incluir java.util. * O simplemente seleccionar cada clase individualmente, depende del estilo. Tenga en cuenta que no quiere using namespace std al inicio de su archivo / amplio alcance, ya que contaminará el espacio de nombres y posiblemente tendrá conflictos, lo que frustrará el punto de los espacios de nombres. Pero si tiene una función que usa mucho STL, desordena el código para tener un revoltijo de sintaxis de prefijación en su lógica y probablemente debería considerar using namespace std (cuando usa una variedad de clases) o el using individual de s ( cuando se usan algunas clases a menudo).


Ambos

using std::string;

y

using namespace std;

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 se debe hacer en los archivos de encabezado. No tiene control sobre quién incluirá su 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 dividir 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 nombre. 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 quieres poner todo el espacio de nombres en tu cabeza :-), depende de ti. Si bien los efectos se limitan a una sola unidad de compilación, es aceptable.


Esta discusión seguirá viva siempre que el IDE con el que trabaje no sea lo suficientemente flexible como para mostrar u ocultar la información exacta que necesita.

Eso es porque lo que desea que su código se vea depende de la tarea en cuestión.

Al crear mi código fuente, prefiero ver exactamente qué clase estoy usando: ¿es std::string o la BuzFlox::Obs::string ?

Al diseñar el flujo de control, ni siquiera estoy interesado en los tipos de variables, pero quiero un enfoque en if ''s y while '' s y continue ''s.

Así que este es mi consejo:

Dependiendo de la audiencia de su código y del poder de sus herramientas, elija la manera que sea más fácil de leer o que brinde la mayor cantidad de información.


Excluyendo lo básico (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 debes poner

using namespace std

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

using std::swap

Como si hubiera una versión especializada de swap, el compilador usará eso, de lo contrario recurrirá a std :: swap

Si llama a std :: swap, siempre usa la versión básica, que no llamará a la versión optimizada (si existe).


Hay varias formas de arreglar eso.

Primero: use como lo que hizo.

Segundo: do namespace S = std; , reduciendo 2 caracteres.

Tercero: use static .

Cuarto: no use los nombres que usa de manera std .


La mayoría de los usuarios de C ++ están contentos de leer std::string , std::vector , etc. De hecho, al ver un vector procesar me pregunto si este es el std::vector o un std::vector diferente definido por el usuario.

Siempre estoy en contra de using namespace std; . Importa todo tipo de nombres en el espacio de nombres global y puede causar todo tipo de ambigüedades no obvias.

Aquí hay algunos identificadores comunes que están en el std nombres std : count, sort, find, equal, reverse. Tener una variable local llamada count significa que using namespace std no le permitirá usar count lugar de std::count .

El ejemplo clásico de un conflicto de nombre no deseado es algo como lo siguiente. Imagina que eres un principiante y no sabes sobre std::count . Imagina que estás usando algo más en <algorithm> o ha sido arrastrado por un encabezado aparentemente no relacionado.

#include <algorithm> using namespace std; int count = 0; int increment() { return ++count; // error, identifier count is ambiguous }

El error suele ser largo y antipático porque std::count es una plantilla con algunos tipos largos anidados.

Sin embargo, esto está bien, porque std::count entra en el espacio de nombres global y el recuento de funciones lo oculta.

#include <algorithm> using namespace std; int increment() { static int count = 0; return ++count; }

Tal vez, sorprendentemente, esto está bien. Los identificadores importados en un alcance declarativo aparecen en el espacio de nombres común que incluye tanto dónde están definidos como dónde se importan. En otras palabras, std::count es visible como count en el espacio de nombres global, pero solo dentro del increment .

#include <algorithm> int increment() { using namespace std; static int count = 0; return ++count; }

Y por razones similares, el count es ambiguo aquí. using namespace std no provoca std::count , oculta el count externo como podría esperarse. La using namespace regla del using namespace significa que std::count ve (en la función de increment ) como si se hubiera declarado en el ámbito global, es decir, en el mismo ámbito que int count = 0; y por lo tanto, causando la ambigüedad.

#include <algorithm> int count = 0; int increment() { using namespace std; return ++count; // error ambiguous }


Los espacios de nombres mantienen el código contenido para evitar la confusion y la contaminación de las firmas de función.

Here una demostración completa y documentada del uso proper espacio de nombres :

#include <iostream> #include <cmath> // Uses ::log, which would be the log() here if it were not in a namespace, see https://.com/questions/11892976/why-is-my-log-in-the-std-namespace // Silently overrides std::log //double log(double d) { return 420; } namespace uniquename { using namespace std; // So we don''t have to waste space on std:: when not needed. double log(double d) { return 42; } int main() { cout << "Our log: " << log(4.2) << endl; cout << "Standard log: " << std::log(4.2); return 0; } } // Global wrapper for our contained code. int main() { return uniquename::main(); }

Salida:

Our log: 42 Standard log: 1.43508


Nunca debe 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 ven vector o string sin std:: , así que creo que no using namespace std es mejor. Por lo tanto, defiendo que nunca using namespace std en absoluto.

Si siente que debe hacerlo, agregue declaraciones de uso local como using std::vector . Pero pregúntese: ¿qué vale esto? Una línea de código se escribe una vez (quizás dos veces), pero se lee diez, cien o mil veces. El esfuerzo de tipeo guardado es agregar una declaración de uso o directiva es marginal en comparación con el esfuerzo de leer el código.

Con esto 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 esa compañía, nadie está usando directivas o declaraciones más. (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 de using generalmente no lo han probado en un solo 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 que es necesario (especialmente en código genérico) para recoger sobrecargas de swap() que no se pueden poner en el std nombres std (porque no se nos permite poner sobrecargas de funciones std en este espacio de nombres).


Nunca use el espacio de nombres en el alcance global en un archivo de encabezado. Eso puede conducir 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 menos bien recortadas.

  • Poner un espacio de nombres de uso usando std trae todos los símbolos de esos espacios de nombres. Esto puede ser problemático ya que casi ningún cuerpo conoce todos los símbolos que existen (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 de 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 casos controlados. Y si ocurre un error, se detecta en el archivo que tiene el problema.

  • Poniendo usando std :: name; tiene la ventaja de la simplicidad 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ícitamente agrega un poco de desorden, pero creo que es la práctica menos problemática.

En mi proyecto, utilizo la calificación explícita para todos los nombres, acepto usar std :: name, lucho contra usar namespace std (tenemos un intérprete de lisp que tiene su propio tipo de lista y por lo tanto el conflicto es seguro).

Para otros espacios de nombres, también debe tener en cuenta las convenciones de denominación utilizadas. Sé de un proyecto que usa el espacio de nombres (para versionar) y el prefijo sobre nombres. Hacer un using namespace X es casi sin riesgo y no hacerlo conduce a un código de aspecto estúpido PrefixNS::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 no calificado. La búsqueda dependiente de argumentos 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 lenguaje de extensión con un dialecto de lisp. Nuestro intérprete tiene un archivo de inclusión, lisp.h que contiene

typedef struct list {} list;

Tuvimos que integrar y adaptar algunos códigos (que llamaré "motor") que se veía así:

#include <list> ... using std::list; ... void foo(list const&) {}

Así que modificamos así:

#include <list> #include "module.h" ... using std::list; ... void foo(list const&) {}

Bueno. Todo funciona Algunos meses después, "module.h" se modificó para incluir "list.h". Las pruebas pasaron El "módulo" no se modificó de manera que afectara su ABI, por lo que la biblioteca "engine" podría utilizarse sin volver a compilar a sus usuarios. Las pruebas de integración estaban bien. Nuevo "módulo" publicado. La siguiente compilación del motor se rompió cuando su código no se modificó.


Para mí, prefiero usar :: cuando sea posible.

std::list<int> iList;

Odio escribir:

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++) { // }

Con suerte, con C ++ 0x escribiría esto:

for(auto i = iList.begin(); i != iList.end(); i++) { // }

Si el espacio de nombres es muy largo,

namespace dir = boost::filesystem; dir::directory_iterator file("e:/boost"); dir::directory_iterator end; for( ; file != end; file++) { if(dir::is_directory(*file)) std::cout << *file << std::endl; }


Por qué no, por ejemplo

typedef std::vector<int> ints_t; ints_t ints1; .... ints_t ints2;

en lugar de la poco manejable

std::vector<int> ints1; ... std::vector<int> ints2;

Encuentro eso mucho más legible y es mi estándar para la codificación.

Incluso puede usarlo para incluir información semántica para el lector. Por ejemplo, considere los prototipos de función

void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);

¿Cuál es el valor de retorno?

¿Qué tal si

typedef std::vector<unsigned int> values_t; typedef std::vector<unsigned int> histogram_t; ... void getHistogram(values_t&, histogram_t&);


Primero, algo de terminología:

  • using-declaration : using std::vector;
  • using-directive : using namespace std;

Creo que el uso de directivas using está bien, siempre que no se utilicen en el ámbito global en un archivo de encabezado. Entonces teniendo

using namespace std;

en su archivo .cpp no ​​es realmente un problema, y ​​si resulta serlo, está completamente bajo su control (y puede incluso tener un alcance en bloques particulares, si así lo desea). No veo ninguna razón para enredar el código con una gran cantidad de calificadores std:: , simplemente se convierte en un montón de ruido visual. Sin embargo, si no está usando un montón de nombres del std nombres std en su código, tampoco veo ningún problema para omitir la directiva. Es una tautología: si la directiva no es necesaria, entonces no hay necesidad de usarla.

De manera similar, si puede salir con unas pocas declaraciones de uso (en lugar de usar-directivas ) para tipos específicos en el std nombres estándar, entonces no hay razón por la que no deba tener solo esos nombres específicos ingresados ​​en el espacio de nombres actual. Por la misma razón, creo que sería una locura y una molestia de contabilidad tener 25 o 30 declaraciones de uso cuando una sola directiva de uso también lo haga.

También es bueno tener en cuenta que hay momentos en los que debe usar una declaración de uso. Consulte "Artículo 25: Considere la posibilidad de soporte para un intercambio no lanzado" de Scott Meyers de Effective C ++, Third Edition. Para tener una función genérica, con plantilla, use el ''mejor'' método de intercambio para un tipo parametrizado, necesita hacer uso de una declaración de uso y una búsqueda dependiente del argumento (también conocida como ADL o búsqueda de Koenig):

template< typename T > void foo( T& x, T& y) { using std::swap; // makes std::swap available in this function // do stuff... swap( x, y); // will use a T-specific swap() if it exists, // otherwise will use std::swap<T>() // ... }

Creo que deberíamos ver 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 de espacios de nombres se usan en esos idiomas es acercándolos al alcance actual en masa con el equivalente de una directiva using. Esto no causa problemas muy extendidos, y las pocas veces que se trata de un problema se manejan de forma "excepcional" al tratar los nombres en cuestión a través de nombres totalmente calificados o por aliasing, como se puede hacer en C ++.

Herb Sutter y Andrei Alexandrescu tienen esto que decir en "Artículo 59: No escribir usos del espacio 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:

En resumen: puede y debe usar el espacio de nombres usando declaraciones y directivas generosamente en sus archivos de implementación después de las directivas #include y sentirse bien al respecto. A pesar de las afirmaciones repetidas de lo contrario, el espacio de nombres que usa declaraciones y directivas no son malas y no anulan el propósito de los espacios de nombres. Más bien, son lo que hace que los espacios de nombres sean utilizables.

Stroupstrup se cita a menudo diciendo: "No contaminar 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:

Una declaración de uso agrega un nombre a un ámbito local. A using-directive no; simplemente hace que los nombres sean accesibles en el ámbito en el que fueron declarados. Por ejemplo:

namespaceX { int i , j , k ; } int k ; void f1() { int i = 0 ; using namespaceX ; // make names from X accessible i++; // local i j++; // X::j k++; // error: X::k or global k ? ::k ++; // the global k X::k ++; // X’s k } void f2() { int i = 0 ; using X::i ; // error: i declared twice in f2() using X::j ; using X::k ; // hides global k i++; j++; // X::j k++; // X::k }

Un nombre declarado localmente (declarado por una declaración ordinaria o por una declaración de uso) oculta declaraciones no locales del mismo nombre, y cualquier sobrecarga ilegal del nombre se detecta en el punto de declaración.

Tenga en cuenta el error de ambigüedad para k++ en f1() . Los nombres globales no tienen preferencia sobre los nombres de espacios de nombres accesibles en el ámbito global. Esto proporciona una protección significativa contra los conflictos de nombres accidentales y, lo que es más importante, garantiza que no se obtengan ventajas de la contaminación del espacio de nombres global.

Cuando las bibliotecas que declaran muchos nombres son accesibles a través de using-directives, es una ventaja significativa que los choques de nombres no utilizados no se consideran errores.

...

Espero ver una disminución radical en el uso de nombres globales en nuevos programas que utilizan espacios de nombres en comparación con los programas tradicionales C y C ++. Las reglas para los espacios de nombres se crearon específicamente para no ofrecer ventajas a un usuario "perezoso" de nombres globales por encima de alguien que tiene cuidado de no contaminar el alcance global.

¿Y cómo tiene uno la misma ventaja que un "usuario perezoso de nombres globales"? Aprovechando la directiva de uso, que hace que los nombres de un espacio de nombres estén disponibles de forma segura para el alcance actual.

Tenga en cuenta que hay una distinción: los nombres en el std nombres std disponibles para un ámbito con el uso adecuado de una directiva de uso (colocando la directiva después de los #includes ) no contaminan el espacio de nombres global. Simplemente está haciendo que esos nombres estén disponibles fácilmente y con una protección continua contra los enfrentamientos.


Si no tiene riesgo de conflictos de nombres en su código con std y otras bibliotecas, puede usar:

using namespace std;

Pero si quiere saber con precisión la dependencia de su código para la documentación o existe el riesgo de conflictos de nombres, use la otra forma:

using std::string; using std::cout;

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 pesadez en el código ...


using namespace std importa el contenido del std nombres std en el actual. Por lo tanto, la ventaja es que no tendrá que escribir std:: en frente de todas las funciones de ese espacio de nombres. Sin embargo, puede suceder que tenga diferentes espacios de nombres que tengan funciones del mismo nombre. Por lo tanto, puede terminar no llamando a la persona que desea.

Especificar manualmente cuáles quieres importar en std evita que eso suceda, pero puede dar lugar a una larga lista de uso al principio de tu archivo, que algunos desarrolladores encontrarán desagradables;)!

Personalmente, prefiero especificar el espacio de nombres cada vez que utilizo una función, excepto cuando el espacio de nombres es demasiado largo, en cuyo caso pongo algunos al comienzo del archivo.

EDITAR: como se señala en otra respuesta, nunca debe poner un using namespace de 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.