"Usar el espacio de nombres" en los encabezados de C++
namespaces header-files (9)
Como todas las cosas en la programación, el pragmatismo debería conquistar el dogmatismo, IMO.
Mientras tome la decisión en todo el proyecto ("Nuestro proyecto usa STL extensivamente, y no queremos tener que anteponer todo con std ::."), No veo el problema. Lo único que te arriesgas es 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 único archivo de encabezado (no privado), puedo ver cómo generaría confusión entre el equipo y debería evitarse.
En todos nuestros cursos de c ++, todos los profesores siempre using namespace std;
justo después de #include
s en sus archivos .h
Esto me parece peligroso ya que al incluir ese encabezado en otro programa obtendré el espacio de nombre importado en mi programa, tal vez sin darme cuenta, con la intención o sin querer (la inclusión del encabezado puede estar muy anidada).
Así que mi pregunta es doble: ¿tengo razón en que el using namespace
no debe usarse en los archivos de encabezado, y / o hay alguna forma de deshacerlo, algo así como:
//header.h
using namespace std {
.
.
.
}
Una pregunta más en la misma línea: debe un archivo de encabezado #include
todos los encabezados que necesita el archivo .cpp
correspondiente, solo aquellos que son necesarios para las definiciones de encabezado y dejar el archivo .cpp
el resto, o ninguno y declarar todo necesita como extern
?
El razonamiento detrás de la pregunta es el mismo que el anterior: no quiero sorpresas al incluir archivos .h
.
Además, si estoy en lo correcto, ¿es este un error común? Me refiero a la programación del mundo real y a los proyectos "reales" que existen.
Gracias.
Con respecto a "¿Hay alguna manera de deshacer [a using
declaration]?"
Creo que es útil señalar que el using
declaraciones se ve afectado 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
Entonces efectivamente. Al limitar el alcance de la declaración de using
su efecto solo dura dentro de ese alcance; está ''deshecho'' cuando ese alcance finaliza.
Cuando la declaración using
se declara en un archivo fuera de cualquier otro ámbito, tiene un alcance de archivo y afecta a todo en ese archivo.
En el caso de un archivo de encabezado, si la declaración using
está en el alcance del archivo, esto se extenderá al alcance de cualquier archivo en el que se incluya el encabezado.
Consulte 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; vea las respuestas actualizadas a las preguntas SO:
El estándar de codificación GSFC C ++ dice:
§3.3.7 Cada archivo de encabezado
#include
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; otros#includes
deben colocarse en el archivo fuente.
La primera de las preguntas con referencias cruzadas ahora incluye una cita del estándar de codificación GSFC C, y la razón fundamental, pero la sustancia termina siendo la misma.
Creo que puedes usar ''usar'' en los encabezados de C ++ de forma segura si escribes tus 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.
Debe tener cuidado al incluir encabezados dentro de los encabezados. En proyectos grandes, puede crear una cadena de dependencia muy enredada que desencadene reconstrucciones más grandes / más largas de lo que realmente era necesario. Consulte este artículo y su seguimiento para conocer más sobre la importancia de una buena estructura física en los proyectos de 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 la declaración directa 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 alcance explícito del espacio de nombres en mis archivos de encabezado, y solo pongo un using namespace
de using namespace
en mis archivos cpp.
Definitivamente NO deberías using namespace
de using namespace
en los encabezados precisamente por la razón que dices, que puede cambiar inesperadamente el significado del código en cualquier otro archivo que incluya ese encabezado. No hay forma de deshacer un using namespace
que es otra razón por la que es tan peligroso. Normalmente solo uso grep
o similar para asegurarme de que el using namespace
no se llame en los encabezados en lugar de intentar algo más complicado. Probablemente los verificadores de código estático también lo señalan.
El encabezado debe incluir solo los encabezados que necesita compilar. Una manera fácil de hacer cumplir esto es incluir siempre el encabezado de cada archivo fuente como lo primero, antes que cualquier otro encabezado. Entonces, el archivo fuente no podrá compilarse si el encabezado no es autónomo. En algunos casos, por ejemplo, al referirse a clases de detalle de implementación dentro de una biblioteca, puede usar declaraciones forward en lugar de #include
porque tiene control total sobre la definición de dicha clase declarada forward.
No estoy seguro de que lo llame común, pero definitivamente aparece de vez en cuando, generalmente escrito por nuevos programadores que no están al tanto de las consecuencias negativas. Normalmente, solo un poco de educación sobre los riesgos se ocupa de cualquier problema, ya que es relativamente fácil de solucionar.
Punto 59 en "Estándares de codificación C ++" de Sutter y Alexandrescu: 101 Reglas, pautas y mejores prácticas ":
- No escriba los usos del espacio de nombres en un archivo de encabezado 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 ++.
Tiene razón en que using namespace
de using namespace
en el encabezado es peligroso. No sé cómo deshacerlo. Es fácil de detectar, sin embargo, solo busca using namespace
de using namespace
en los archivos de encabezado. Por esa última razón, no es 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, las personas intentan minimizar la cantidad de archivos incluidos, porque cuanto menos incluyas, más rápido se compilará. Eso ahorra tiempo a todos. Sin embargo, si el archivo de cabecera supone que algo debe incluirse antes, debe incluirlo. De lo contrario, hace que los encabezados no sean autocontenidos.
Tienes razón. Y cualquier archivo solo debe incluir los encabezados necesarios para ese archivo. En cuanto a "¿está haciendo cosas mal comunes en proyectos del mundo real?" - ¡Oh si!