Pregunta ¿Por qué "usar el espacio de nombres estándar" se considera una mala práctica?


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 que es using namespace std considerado una mala práctica? ¿Es ineficiente o corre el riesgo de declarar variables ambiguas (variables que comparten el mismo nombre como una función en std espacio de nombres)? ¿Afecta el rendimiento?


2061
2017-09-21 03:08


origen


Respuestas:


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

using namespace foo;
using namespace bar;

Todo funciona bien, puedes llamar Blah() de Foo y Quux() de 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: importación de Foo 2.0 y Bar Quux() en tu espacio de nombres global. Esto requerirá un esfuerzo para solucionarlo, especialmente si los parámetros de la función coinciden.

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


1746
2017-09-21 03:13



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

La biblioteca Foo 2.0 podría introducir una función, Quux(), esa es una coincidencia inequívocamente mejor para algunas de sus llamadas a Quux() que la bar::Quux() tu código requería años. Entonces tu el código aún compila, pero llama silenciosamente la función incorrecta y Dios sabe qué. Eso es casi tan malo como pueden ser las cosas.

Tenga en cuenta que std espacio de nombres tiene toneladas de identificadores, muchos de los cuales son muy los más comunes (piense list, sort, string, iterator, etc.) que es muy probable que también aparezcan en otros códigos.

Si considera esto poco probable: Hubo una pregunta aquí en Stack Overflow donde casi exactamente sucedió esto (función incorrecta llamada debido a omitida std:: prefijo) aproximadamente medio año después de dar esta respuesta. aquí es otro ejemplo más reciente de tal pregunta. Entonces este es un problema real.


Aquí hay un punto de datos más: hace muchos, muchos años, también solía encontrar molesto tener que prefijar todo de la biblioteca estándar con std::. Luego trabajé en un proyecto donde se decidió desde el principio que ambos using las directivas y declaraciones están prohibidas a excepción de los ámbitos funcionales. ¿Adivina qué? Nos tomó a la mayoría de nosotros pocas semanas acostumbrarnos a escribir el prefijo, y después de unas semanas más, la mayoría de nosotros incluso estuvo de acuerdo en que realmente hizo el código. más legible. Hay una razón para eso: Si le gusta la prosa más corta o más larga es subjetiva, pero los prefijos añaden claridad al código de forma objetiva. No solo el compilador, sino también usted, le resulta más fácil ver a qué identificador se hace referencia.

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 me di cuenta de la frecuencia con la que el alcance de la función (permitido) usingen realidad fue utilizado en el proyecto. Aprecié las fuentes y solo encontré una o dos docenas de lugares donde se usó. Para mí, esto indica que, una vez probados, los desarrolladores no encuentran std:: lo suficientemente doloroso para emplear el uso de directivas incluso una vez cada 100 kLoC, incluso donde se permitió su uso.


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


1147
2017-09-21 09:26



Creo que es malo ponerlo en los archivos de encabezado de tus clases: porque estarías obligando a cualquiera que quiera usar tus clases (al incluir tus archivos de encabezado) a que también 'usen' (es decir, vean todo) esos otros espacios de nombres .

Sin embargo, puede usar 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, porque 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 todavía no es bueno (porque 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 using existe para el código heredado de C ++ y para facilitar la transición a los espacios de nombres, pero es probable que no deba usarla de manera regular, al menos no en su nuevo código de C ++.

Sugiere dos alternativas:

  • Una declaración de uso:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Superarlo y simplemente escribir std ::

    std::cout << "Values:";
    

308
2017-09-21 03:22



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

using namespace std;
using namespace boost;

Un montón de Aumentar las características van al estándar C ++ 0x, y Visual Studio 2010 tiene muchas características C ++ 0x, por lo que de repente estos programas no se estaban compilando.

Por lo tanto, evitando using namespace X; es una forma de protección contra el futuro, una forma de asegurarse de que un cambio en las bibliotecas y / o archivos de encabezado en uso no rompa un programa.


197
2017-10-28 17:37



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

Resumen

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

Corolario: en archivos de encabezado, no escriba el nivel de espacio de nombres usando directivas o usando declaraciones; en su lugar, califica explícitamente el nombre del espacio de nombres de todos los nombres. (La segunda regla se sigue de la primera, porque los encabezados nunca pueden saber qué otro header #includes podría 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 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.


159
2017-11-03 20:00



No se debe usar el uso de directivas en el alcance 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 Argument Dependent Lookup).


103
2017-09-21 15:47



No lo uses globalmente

Se considera "malo" solo cuando usado globalmente. Porque:

  • Abarrotas el espacio de nombres en el que estás programando.
  • Los lectores tendrán dificultades para ver de dónde proviene un identificador en particular, cuando usted usa muchos using namespace xyz.
  • Lo que sea cierto para otro los lectores de su código fuente son aún más cierto para el lector más frecuente: usted mismo. Vuelve dentro de uno o dos años y eche un vistazo ...
  • Si solo hablas de using namespace std es posible que no estés al tanto de todo lo que agarras, y cuando agregas otro #include o pase a una nueva revisión de C ++, puede que tenga conflictos de nombres de los que no tenía conocimiento.

Puedes usarlo localmente

Adelante y úsalo localmente (casi) libremente. Esto, por supuesto, evita que se repita std:: - y la repetición también es mala

Un modismo para usarlo localmente

En C ++ 03 había una frase idiomática - código repetitivo - para implementar un swap función 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á el std::swap para value_, es decir void std::swap(int, int).
  • Si tienes una sobrecarga void swap(Child&, Child&) implementado el compilador lo elegirá.
  • Si lo haces no tener esa sobrecarga que usará el compilador void std::swap(Child&,Child&) y haz tu mejor esfuerzo para intercambiar estos.

Con C ++ 11 no hay razón para usar este patrón más. La implementación de std::swap fue cambiado para encontrar una posible sobrecarga y elegirlo.


80
2018-01-18 09:34



Si importa los archivos de encabezado correctos, de repente tiene nombres como hex, left, plus o count en su alcance global. Esto podría sorprender si no eres consciente de que std:: contiene estos nombres Si también intentas usar estos nombres localmente, puede provocar cierta confusión.

Si todo lo estándar está en su propio espacio de nombres, no tiene que preocuparse por las colisiones de nombres con su código u otras bibliotecas.


71
2017-09-21 03:23