"uso del espacio de nombres" en cabeceras de c++


En todos nuestros cursos de c++, todos los profesores siempre ponen using namespace std; justo después de las #includes en sus archivos .h. Esto me parece peligroso desde entonces al incluir ese encabezado en otro programa obtendré el espacio de nombres importado a mi programa, tal vez sin darme cuenta, con la intención o queriéndolo (la inclusión del encabezado puede estar muy anidada).

Así que mi pregunta es doble: ¿Tengo razón en que using namespace no debe usarse en archivos de encabezado, y / o hay alguna manera de deshacerlo, algo como:

//header.h
using namespace std {
.
.
.
}

Una pregunta más en la misma línea: ¿Debería un archivo de cabecera #include todos los encabezados que le corresponden .cpp necesita, solo los que se necesitan para las definiciones de encabezado y dejar que el archivo .cpp #include el resto, o ninguno y declarar todo lo que necesita como extern?
El razonamiento detrás de la pregunta es el mismo que el anterior: No quiero sorpresas al incluir archivos .h.

También, si tengo razón, ¿es esto un error común? Quiero decir en el mundo real programación y en proyectos "reales" por ahí.

Gracias.

Author: baruch, 2011-05-01

9 answers

Definitivamente NO debe usar using namespace en encabezados precisamente por la razón que dice, que puede cambiar inesperadamente el significado del código en cualquier otro archivo que incluya ese encabezado. No hay manera de deshacer un using namespace que es otra razón por la que es tan peligroso. Normalmente solo uso grep o similares para asegurarme de que using namespace no esté siendo llamado en encabezados en lugar de intentar algo más complicado. Probablemente los comprobadores de código estáticos marcan esto también.

El encabezado debe incluir solo cabeceras que necesita compilar. Una manera fácil de hacer cumplir esto es incluir siempre el encabezado propio de cada archivo fuente como lo primero, antes que cualquier otro encabezado. Entonces el archivo fuente fallará al compilar si el encabezado no es autónomo. En algunos casos, por ejemplo, haciendo referencia a las clases implementation-detail dentro de una biblioteca, puede usar declaraciones forward en lugar de #include porque tiene control total sobre la definición de dicha clase forward declarada.

No estoy seguro de que lo llamaría común, pero definitivamente aparece de vez en cuando, generalmente escrito por nuevos programadores que no son conscientes de las consecuencias negativas. Por lo general, solo un poco de educación sobre los riesgos se encarga de cualquier problema, ya que es relativamente fácil de solucionar.

 94
Author: Mark B,
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-02-13 00:14:06

Artículo 59 en " C++ Coding Standards: 101 Rules, Guidelines, and Best Practices "de Sutter y Alexandrescu:

  1. No escriba el uso de espacios de nombres en un archivo de cabecera o antes de un #include. 108

Los títulos de todas las directrices están en http://www.gotw.ca/publications/c++cs.htm, pero los detalles son una lectura obligada para los desarrolladores de C++.

 21
Author: Andy Thomas,
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
2016-03-10 09:09:03

Debe tener cuidado al incluir encabezados dentro de los encabezados. En proyectos grandes, puede crear una cadena de dependencias muy enredada que desencadena reconstrucciones más grandes o más largas de lo que realmente eran necesarias. Echa un vistazo a este artículo y su seguimiento para aprender más sobre la importancia de una buena estructura física en proyectos C++.

Solo debe incluir encabezados dentro de un encabezado cuando sea absolutamente necesario (siempre que se necesite la definición completa de una clase), y usar forward declaración siempre que pueda (cuando se requiere la clase es un puntero o una referencia).

En cuanto a los espacios de nombres, tiendo a usar el ámbito de espacio de nombres explícito en mis archivos de encabezado, y solo pongo un using namespace en mis archivos cpp.

 12
Author: Mike O'Connor,
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
2011-05-01 16:19:02

Echa un vistazo a los estándares de codificación del Goddard Space Flight Center (para C y C++). Eso resulta ser un poco más difícil de lo que solía ser-ver las respuestas actualizadas a las preguntas SO:

El estándar de codificación C++ de GSFC dice:

§3.3.7 Cada archivo de cabecera debe #include los archivos que necesita compilar, en lugar de forzar a los usuarios a #include los archivos necesarios. #includes se limitará a lo que necesita el encabezado; otro #includes debe colocarse en el archivo fuente.

La primera de las preguntas cruzadas ahora incluye una cita del estándar de codificación GSFC C, y la justificación, pero la sustancia termina siendo la misma.

 6
Author: Jonathan Leffler,
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-05-23 11:54:16

Tienes razón en que using namespace en el encabezado es peligroso. No sé cómo deshacerlo. Es fácil detectarlo, sin embargo, solo busque using namespace en los archivos de encabezado. Por esa última razón es poco común en proyectos reales. Los compañeros de trabajo más experimentados pronto se quejarán si alguien hace algo así.

En proyectos reales la gente intenta minimizar la cantidad de archivos incluidos, porque cuanto menos se incluye, más rápido se compila. Eso ahorra tiempo a todos. Sin embargo, si el archivo de encabezado asume que algo debe ser incluido antes de que entonces debe incluir a sí mismo. De lo contrario, hace que los encabezados no sean autónomos.

 5
Author: Öö Tiib,
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
2011-05-01 17:15:01

Tienes razón. Y cualquier archivo solo debe incluir las cabeceras necesarias para ese archivo. En cuanto a " ¿es común hacer las cosas mal en proyectos del mundo real?"- ¡oh, sí!

 4
Author: Neil Butterworth,
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
2011-05-01 15:52:33

Como todas las cosas en la programación, el pragmatismo debería vencer al dogmatismo, IMO.

Siempre y cuando tome la decisión en todo el proyecto ("Nuestro proyecto usa STL ampliamente, y no queremos tener que anteponer todo con std::."), No veo el problema. Lo único que arriesgas son colisiones de nombres, después de todo, y con la ubicuidad de STL es poco probable que sea un problema.

Por otro lado, si fue una decisión de un desarrollador en un solo (no privado) header-file, puedo ver cómo generaría confusión entre el equipo y debería evitarse.

 3
Author: ijprest,
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
2011-05-01 16:29:36

Creo que puede usar' using ' en encabezados C++ de forma segura si escribe sus declaraciones en un espacio de nombres anidado como este:

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
    /*using statements*/

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
    {
        /*declarations*/
    }
}

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;

Esto debería incluir solo las cosas declaradas en 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' sin los espacios de nombres utilizados. Lo he probado en el compilador mingw64.

 2
Author: AnArrayOfFunctions,
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-11-16 17:47:51

Con respecto a "¿Hay alguna manera de deshacer [una declaración using]?"

Creo que es útil señalar que using las declaraciones se ven afectadas por el alcance.

#include <vector>

{   // begin a new scope with {
    using namespace std;
    vector myVector;  // std::vector is used
}   // end the scope with }

vector myOtherVector;   // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified

Tan efectivamente sí. Al limitar el ámbito de aplicación de la declaración using, su efecto solo perdura dentro de ese ámbito de aplicación; queda "deshecho" cuando termina ese ámbito de aplicación.

Cuando la declaración using se declara en un archivo fuera de cualquier otro ámbito, tiene ámbito de archivo y afecta a todo en ese archivo.

En el caso de un archivo de cabecera, si la declaración using está en file-scope esto se extenderá al ámbito de cualquier archivo en el que se incluya el encabezado.

 2
Author: YoungJohn,
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
2016-02-26 18:27:18