c++ - usa - using namespace std programacion




¿Por qué se considera una mala práctica el uso de "namespace std"? (20)

No lo uses globalmente.

Se considera "malo" solo cuando se usa globalmente . Porque:

  • Usted desordena el espacio de nombres que está programando.
  • Los lectores tendrán dificultades para ver de dónde proviene un identificador particular, cuando usa muchos using namespace xyz .
  • Lo que sea cierto para otros lectores de su código fuente es aún más cierto para el lector más frecuente: usted mismo. Vuelve en uno o dos años y echa un vistazo ...
  • Si solo habla sobre el using namespace std es posible que no esté al tanto de todas las cosas que toma, y ​​cuando agrega otro #include o se muda a una nueva revisión de C ++, puede que tenga conflictos de nombre de los que no estaba al tanto.

Puedes usarlo localmente

Adelante y utilízalo localmente (casi) libremente. Esto, por supuesto, le impide la repetición de std:: - y la repetición también es mala.

Un modismo para usarlo localmente.

En C ++ 03 había un modismo, código repetitivo, para implementar una función de swap para tus clases. Se sugirió que realmente use un local using namespace std , o al menos using std::swap :

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

Esto hace la siguiente magia:

  • El compilador elegirá std::swap para value_ , es decir, void std::swap(int, int) .
  • Si tiene una sobrecarga void swap(Child&, Child&) implementado, el compilador lo elegirá.
  • Si no tiene esa sobrecarga, el compilador utilizará void std::swap(Child&,Child&) e intentará intercambiar estos.

Con C ++ 11 ya no hay razón para usar este patrón. La implementación de std::swap se cambió para encontrar una sobrecarga potencial y elegirla.

Otros me han dicho que escribir using namespace std en el código es incorrecto, y que debería usar std::cout y std::cin directamente en su lugar.

¿Por qué el using namespace std una mala práctica? ¿Es ineficiente o corre el riesgo de declarar variables ambiguas (variables que comparten el mismo nombre que una función en el std nombres std )? ¿Afecta el rendimiento?


  1. debe poder leer el código escrito por personas que tienen opiniones diferentes de estilos y mejores prácticas que usted.

  2. Si solo estás usando cout, nadie se confunde. Pero cuando tienes muchos espacios de nombres volando y ves esta clase y no estás exactamente seguro de qué es lo que hace, tener el espacio de nombres explícito actúa como una especie de comentario. Puede ver a primera vista, 'oh, esto es una operación del sistema de archivos' o 'eso es hacer cosas de red'.


El problema de poner el using namespace de using namespace en los archivos de encabezado de sus clases es que obliga a cualquier persona que quiera usar sus clases (al incluir sus archivos de encabezado) también a "usar" (es decir, ver todo en) esos otros espacios de nombres.

Sin embargo, puede sentirse libre de poner una declaración de uso en sus archivos (privados) * .cpp.

Tenga en cuenta que algunas personas no están de acuerdo con que yo diga "siéntase libre" de esta manera, ya que aunque una declaración de uso en un archivo cpp es mejor que en un encabezado (porque no afecta a las personas que incluyen su archivo de encabezado), piensan que aún es así. no es bueno (ya que, dependiendo del código, podría hacer que la implementación de la clase sea más difícil de mantener). Este tema de preguntas frecuentes dice:

La directiva de uso existe para el código C ++ heredado y para facilitar la transición a los espacios de nombres, pero probablemente no debería usarlo regularmente, al menos no en su nuevo código C ++.

El FAQ sugiere dos alternativas:

  • Una declaración de uso:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Sólo escribiendo std ::

    std::cout << "Values:";
    

El uso de muchos espacios de nombres al mismo tiempo es obviamente una receta para el desastre, pero usar JUST espacio de nombres std y solo espacio de nombres std no es tan importante en mi opinión porque la redefinición solo puede ocurrir por su propio código ...

Entonces, considérelas funciones como nombres reservados como "int" o "class" y eso es todo.

La gente debería dejar de ser tan anal al respecto. Tu profesor tenía razón todo el tiempo. Solo usa UN espacio de nombres; ese es el punto central de usar espacios de nombres en primer lugar. Se supone que no debes usar más de uno al mismo tiempo. A menos que sea el tuyo. Así que de nuevo, la redefinición no va a suceder.


Esto no está relacionado con el rendimiento en absoluto. Pero considera esto: estás usando dos bibliotecas llamadas Foo y Bar:

using namespace foo;
using namespace bar;

Todo funciona bien, puedes llamar a Blah() desde Foo y Quux() desde Bar sin problemas. Pero un día se actualiza a una nueva versión de Foo 2.0, que ahora ofrece una función llamada Quux() . Ahora tienes un conflicto: tanto Foo 2.0 como Bar importan Quux() en tu espacio de nombres global. Esto requerirá un poco de esfuerzo para solucionarlo, especialmente si los parámetros de la función coinciden.

Si hubiera usado foo::Blah() y bar::Quux() , entonces la introducción de foo::Quux() no habría sido un evento.


Estoy de acuerdo con todo lo que Greg escribió , pero me gustaría agregar: ¡Incluso puede ser peor de lo que Greg dijo!

Library Foo 2.0 podría introducir una función, Quux() , que es una mejor opción para algunas de sus llamadas a Quux() que la bar::Quux() su código llamó por años. Entonces su código aún se compila , pero silenciosamente llama a la función incorrecta y sabe qué sabe Dios. Eso es tan malo como las cosas pueden llegar.

Tenga en cuenta que el std nombres std tiene toneladas de identificadores, muchos de los cuales son muy comunes ( list reflexión, sort , string , iterator , etc.) que probablemente también aparezcan en otro código.

Si considera que esto es poco probable: hubo una pregunta aquí en en la que casi exactamente sucedió esto (función incorrecta llamada debido a que se omite el prefijo std:: ) aproximadamente medio año después de dar esta respuesta. Here hay otro ejemplo más reciente de tal pregunta. Así que este es un problema real.

Aquí hay un punto de datos más: Hace muchos, muchos años, también me resultaba molesto tener que prefijar todo desde la biblioteca estándar con std:: . Luego trabajé en un proyecto en el que se decidió al principio que tanto las directivas como las declaraciones están prohibidas, excepto para los ámbitos de funciones. ¿Adivina qué? A la mayoría de nosotros nos llevó muy pocas semanas acostumbrarnos a escribir el prefijo, y después de unas pocas semanas, la mayoría de nosotros incluso estuvimos de acuerdo en que hacía que el código fuera más legible . Hay una razón para eso: si te gusta la prosa más corta o más larga es subjetivo, pero los prefijos agregan objetivamente claridad al código. No solo el compilador, sino que a usted también le resulta más fácil ver a qué identificador se refiere.

En una década, ese proyecto creció hasta tener varios millones de líneas de código. Dado que estas discusiones surgen una y otra vez, una vez sentí curiosidad por la frecuencia using que se utilizó el alcance de la función (permitida) en el proyecto. Le pregunté por las fuentes y solo encontré una o dos docenas de lugares donde se usaba. Para mí, esto indica que, una vez que lo intentamos, a los desarrolladores no les resulta lo suficientemente estd std:: suficientemente doloroso como para emplear el uso de directivas, incluso una vez cada 100 kLoC, incluso cuando se permitió su uso.

En pocas palabras: prefijar explícitamente todo no hace ningún daño, requiere muy poco tiempo para acostumbrarse y tiene ventajas objetivas. En particular, hace que el código sea más fácil de interpretar para el compilador y para los lectores humanos, y ese debería ser probablemente el objetivo principal al escribir código.


Los programadores experimentados usan lo que resuelve sus problemas y evitan todo lo que crea nuevos problemas, y evitan las directivas de uso a nivel de archivo de cabecera por esta razón exacta.

Los programadores experimentados también intentan evitar la calificación completa de los nombres dentro de sus archivos fuente. Una razón menor para esto es que no es elegante escribir más código cuando menos código es suficiente a menos que haya buenas razones . Una razón importante para esto es desactivar la búsqueda dependiente de argumentos (ADL).

¿Cuáles son estas buenas razones ? A veces, los programadores quieren desactivar ADL explícitamente, otras veces quieren desambiguar.

Así que lo siguiente está bien:

  1. Directivas de uso a nivel de función y declaraciones de uso dentro de las implementaciones de funciones
  2. Declaraciones de uso de nivel de archivo fuente dentro de archivos fuente
  3. (A veces) directivas de uso de nivel de archivo fuente

No se debe usar la directiva de uso a nivel global, especialmente en los encabezados. Sin embargo, hay situaciones en las que es apropiado incluso en un archivo de encabezado:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; //no problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

Esto es mejor que la calificación explícita ( std::sin , std::cos ...) porque es más corto y tiene la capacidad de trabajar con tipos de punto flotante definidos por el usuario (a través de la búsqueda dependiente de argumentos).


Recientemente me encontré con una queja sobre Visual Studio 2010 . Resultó que casi todos los archivos de origen tenían estas dos líneas:

using namespace std;
using namespace boost;

Muchas de las características de Boost están incorporadas en el estándar C ++ 0x, y Visual Studio 2010 tiene muchas características de C ++ 0x, por lo que de repente estos programas no se estaban compilando.

Por lo tanto, evitando using namespace X; es una forma de prueba de futuro, una forma de asegurarse de que un cambio en las bibliotecas y / o archivos de encabezado en uso no va a romper un programa.


Se trata de gestionar la complejidad. El uso del espacio de nombres atraerá las cosas que no desee y, por lo tanto, posiblemente dificultará la depuración (lo digo, posiblemente). Usar std :: en todo el lugar es más difícil de leer (más texto y todo eso).

Caballos para cursos: administre su complejidad de la mejor manera que pueda y se sienta capaz.


También lo considero una mala práctica. ¿Por qué? Solo un día pensé que la función de un espacio de nombres es dividir cosas, así que no debería estropearlo con tirar todo en una bolsa global. Sin embargo, si uso a menudo 'cout' y 'cin', escribo: using std::cout; using std::cin; using std::cout; using std::cin; en el archivo cpp (nunca en el archivo de encabezado, ya que se propaga con #include ). Pienso que nadie cuerdo nombrará nunca una secuencia de cout o cin . ;)


Versión corta: no use declaraciones o directivas globales en los archivos de encabezado. Siéntase libre de usarlos en los archivos de implementación. Esto es lo que Herb Sutter y Andrei Alexandrescu tienen que decir sobre este tema en los Estándares de codificación de C ++ (en negrita para enfatizar es mío):

Resumen

Los usos del espacio de nombres son para su conveniencia, no para que pueda infligir a otros: nunca escriba una declaración de uso o una directiva de uso antes de una directiva #include.

Corolario: en los archivos de encabezado, no escriba el nivel de espacio de nombres usando directivas o declaraciones; en su lugar, explícitamente espacios de nombres-calificar todos los nombres. (La segunda regla se sigue de la primera, porque los encabezados nunca pueden saber qué otros encabezados #incluye podrían aparecer después de ellos).

Discusión

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


Un ejemplo donde el uso de espacio de nombres arroja un error de compilación debido a la ambigüedad del conteo, que también es una función en la biblioteca de algoritmos.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}

"¿Por qué es 'utilizando espacio de nombres estándar;' ¿Se considera una mala práctica en C ++? "

Lo puse al revés: ¿por qué algunos tipos de caracteres adicionales se consideran engorrosos?

Considere, por ejemplo, escribir una pieza de software numérico, ¿por qué incluso consideraría la posibilidad de contaminar mi espacio de nombres global al cortar "general :: vector" general a "vector" cuando "vector" es uno de los conceptos más importantes del dominio del problema?


Depende de donde se encuentre. Si es un encabezado común, entonces está disminuyendo el valor del espacio de nombres fusionándolo en el espacio de nombres global. Tenga en cuenta que esta podría ser una buena forma de crear módulos globales.


Desde mi experiencia, si tiene varias bibliotecas que usan, por ejemplo cout, pero para un propósito diferente puede usar el mal cout.

Por ejemplo, si escribo en, using namespace std;y using namespace otherlib;y el tipo simplemente cout (que pasa a ser en ambos), en lugar de std::cout(o 'otherlib::cout'), es posible utilizar el equivocado, y obtener errores, es mucho más eficaz y eficiente de usar std::cout.


Estoy de acuerdo con los demás: está pidiendo conflictos de nombres, ambigüedades y el hecho es que es menos explícito. Si bien puedo ver el uso de using, mi preferencia personal es limitarlo. También consideraría fuertemente lo que algunos otros señalaron:

Si desea buscar un nombre de función que pueda ser un nombre bastante común, pero solo desea encontrarlo en el stdespacio de nombres (o al revés, desea cambiar todas las llamadas que NO estén en el espacio de nombres std, espacio de nombres X, ...), Entonces, ¿cómo te propones hacer esto? Podría escribir un programa para hacerlo, pero ¿no sería mejor dedicar tiempo a trabajar en su propio proyecto en lugar de escribir un programa para mantener su proyecto?

Personalmente, en realidad no me importa el std::prefijo. Me gusta más el look que no tenerlo. No sé si eso es porque es explícito y me dice "este no es mi código ... estoy usando la biblioteca estándar" o si es otra cosa, pero creo que se ve mejor. Esto puede ser extraño dado que solo recientemente ingresé a C ++ (usé y sigo haciendo C y otros idiomas por mucho más tiempo y C es mi idioma favorito de todos los tiempos, justo por encima del ensamblaje).

Hay otra cosa, aunque está algo relacionada con lo anterior y lo que otros señalan. Si bien esto puede ser una mala práctica, a veces reservo la std::nameversión estándar de la biblioteca y el nombre para la implementación específica del programa. Sí, de hecho, esto podría morderlo y morderlo con fuerza, pero todo se reduce a que empecé este proyecto desde cero y soy el único programador para ello. Ejemplo: sobrecargo std::stringy lo llamo string. Tengo adiciones útiles. Lo hice en parte debido a mi tendencia de C y Unix (+ Linux) hacia los nombres en minúsculas.

Además de eso, puedes tener alias de espacio de nombres. Aquí hay un ejemplo de dónde es útil que no se haya mencionado. Uso el estándar C ++ 11 y específicamente con libstdc ++. Bueno, no tiene std::regexsoporte completo . Claro que se compila, pero arroja una excepción en el sentido de que es un error en el extremo del programador. Pero es falta de implementación. Así es como lo resolví. Instale la expresión regular de Boost, vincúlela. Luego, hago lo siguiente para que cuando libstdc ++ se haya implementado por completo, solo necesite eliminar este bloque y el código permanezca igual:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;  
}

No discutiré si es una mala idea o no. Sin embargo, argumentaré que lo mantiene limpio para MI proyecto y al mismo tiempo lo hace específico: es cierto que tengo que usar Boost BUT. Lo estoy usando como libstdc ++ finalmente lo tendrá. Sí, comenzar su propio proyecto y comenzar con un estándar (...) desde el principio va muy lejos con la ayuda del mantenimiento, el desarrollo y todo lo relacionado con el proyecto.

Editar:
Ahora que tengo tiempo, solo para aclarar algo. Realmente no creo que sea una buena idea usar el nombre de una clase / lo que sea en el STL de forma deliberada y más específicamente en lugar de. La cadena es la excepción (ignore la primera, la anterior o la segunda aquí, haga un juego de palabras si es necesario) para mí, ya que no me gustó la idea de 'Cadena'. Tal como está, todavía estoy muy sesgado hacia C y sesgado contra C ++. Los detalles ahorradores, gran parte de lo que trabajo se ajustan a C más (pero fue un buen ejercicio y una buena manera de hacerme a mí mismo. Aprender otro idioma y b. Tratar de no tener menos prejuicios contra objetos / clases / etc. Como de mentalidad menos cerrada, menos arrogante, más aceptando). Pero lo que es útil es lo que algunos ya sugirieron: de hecho, sí uso la lista (es bastante genérico, ¿no es así?),ordenar (lo mismo) para nombrar dos que causaría un choque de nombres si tuviera que hacerusing namespace std;Por eso, para ese fin, prefiero ser específico, tener el control y saber que si pretendo que sea el uso estándar, tendré que especificarlo. En pocas palabras: no se permite suponer.

Y en cuanto a hacer parte de las expresiones regulares de Boost std. Lo hago para una futura integración y, una vez más, admito que esto es un prejuicio, no creo que sea tan feo como lo boost::regex:: ...que de hecho es otra cosa para mí. Hay muchas cosas en C ++ que todavía tengo que aceptar en apariencia y métodos (otro ejemplo: las plantillas variadic versus las args [¡aunque admito que las plantillas variadic son muy útiles!]). Incluso aquellos que sí acepto fueron difíciles Y todavía tengo problemas con ellos.


No creo que sea necesariamente una mala práctica en todas las condiciones, pero debe tener cuidado al usarla. Si está escribiendo una biblioteca, probablemente debería usar los operadores de resolución de alcance con el espacio de nombres para evitar que su biblioteca se tope con otras bibliotecas. Para el código de nivel de aplicación, no veo nada malo en ello.


Para responder a tu pregunta, lo veo de esta manera en la práctica: muchos programadores (no todos) invocan el espacio de nombres std. Por lo tanto, uno debe tener el hábito de NO usar cosas que incidan o usen los mismos nombres que están en el espacio de nombres estándar. Se trata de un gran acuerdo, pero no tanto en comparación con el número de posibles palabras coherentes y seudónimos que se pueden encontrar estrictamente.

Quiero decir realmente ... decir "no confíes en que esté presente" es solo hacer que confíes en que NO esté presente. Siempre vas a tener problemas para pedir fragmentos de código y repararlos constantemente. Simplemente mantenga sus cosas definidas por el usuario y prestadas en un alcance limitado como deberían y con MUCHO ahorro de globales (honestamente, los globales deberían ser siempre un último recurso para los propósitos de "compilar ahora, cordura más adelante"). Realmente creo que es un mal consejo de tu profesor porque usar std funcionará tanto para "cout" como para "std :: cout" pero NO usar std solo funcionará para "std :: cout". No siempre tendrás la suerte de escribir todo tu propio código.

NOTA: No se centre demasiado en los problemas de eficiencia hasta que realmente aprenda un poco sobre cómo funcionan los compiladores. Con un poco de experiencia en codificación, no tiene que aprender mucho sobre ellos antes de darse cuenta de lo mucho que pueden generalizar un buen código en algo simple. Tan simple como si escribieras todo en C. El buen código es tan complejo como debe ser.


Un ejemplo concreto para aclarar la inquietud. Imagina que tienes una situación en la que tienes 2 bibliotecas, foo y bar, cada una con su propio espacio de nombres:

namespace foo {
    void a(float) { /* does something */ }
}

namespace bar {
    ...
}

Ahora digamos que usas foo y bar juntos en tu propio programa de la siguiente manera:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

En este punto todo está bien. Cuando ejecutas tu programa, 'hace algo'. Pero luego actualizas la barra y digamos que ha cambiado para ser como:

namespace bar {
    void a(float) { /* does something completely different */ }
}

En este punto obtendrá un error de compilación:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

Por lo tanto, deberá realizar un mantenimiento para aclarar qué 'a' quiso decir (es decir foo::a). Probablemente sea indeseable, pero afortunadamente es bastante fácil (solo agregue foo::delante de todas las llamadas para aque el compilador marque como ambiguo).

Pero imagina un escenario alternativo donde la barra cambiara para verse así:

namespace bar {
    void a(int) { /* does something completely different */ }
}

En este punto, su llamada a(42)se une repentinamente a en bar::alugar de foo::ay en lugar de hacer "algo" hace "algo completamente diferente". No hay advertencia del compilador ni nada. Tu programa simplemente comienza a hacer algo completamente diferente que antes.

Cuando usas un espacio de nombres estás arriesgando un escenario como este, por lo que la gente se siente incómoda al usar espacios de nombres. Cuantas más cosas haya en un espacio de nombres, mayor será el riesgo de conflicto, por lo que las personas podrían sentirse aún más incómodas al usar el espacio de nombres estándar (debido a la cantidad de cosas en ese espacio de nombres) que otros espacios de nombres.

En última instancia, se trata de un compromiso entre la capacidad de escritura y la fiabilidad / mantenimiento. La legibilidad también puede influir, pero podría ver argumentos para ello. Normalmente, diría que la confiabilidad y la capacidad de mantenimiento son más importantes, pero en este caso, usted pagará constantemente el costo de la capacidad de escritura por un impacto bastante raro de confiabilidad / mantenimiento. La "mejor" compensación determinará su proyecto y sus prioridades.





c++-faq