En todos nuestros cursos de C ++, todos los profesores siempre colocan using namespace std;
justo después de la #include
s en sus .h
archivos. Esto me parece peligroso, ya que al incluir ese encabezado en otro programa, obtendré el espacio de nombres importado a mi programa, tal vez sin darme cuenta, tener la intención o quererlo (la inclusión del encabezado puede estar muy profundamente anidada).
Entonces, mi pregunta es doble: ¿tengo razón en que using namespace
no debería usarse en archivos de encabezado, y / o hay alguna forma de deshacerlo, algo como:
//header.h
using namespace std {
.
.
.
}
Una pregunta más en la misma línea: ¿Debería un encabezado archivar #include
todos los encabezados que .cpp
necesita su archivo correspondiente , solo aquellos que son necesarios para las definiciones de encabezado y dejar el .cpp
archivo #include
el resto, o ninguno y declarar todo lo que necesita extern
?
El razonamiento detrás de la pregunta es el mismo que el anterior: no quiero sorpresas al incluir .h
archivos.
Además, si estoy en lo cierto, ¿es este un error común? Me refiero a la programación del mundo real y a los proyectos "reales" que existen.
Gracias.
fuente
using namespace
declaraciones, puede usar el nombre completo para resolver el problema.Respuestas:
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 forma de deshacer una,using namespace
que es otra razón por la que es tan peligrosa. Por lo general, solo usogrep
o similar para asegurarme de queusing 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 señalan esto.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 de origen no se podrá compilar si el encabezado no es autónomo. En algunos casos, por ejemplo, refiriéndose a las clases de detalles de implementación dentro de una biblioteca, puede usar declaraciones hacia adelante en lugar de
#include
porque tiene control total sobre la definición de dicha clase declarada hacia adelante.No estoy seguro de si 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 soluciona cualquier problema, ya que es relativamente fácil de solucionar.
fuente
using
declaraciones en nuestros.cpp
archivos? las3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
s son la muerte hasta la punta de los dedos.template
funciones, que se supone que están en los encabezados?typedefs
?using
declaraciones dentro de.cpp
archivos sin mucha preocupación porque el alcance se limitará solo a ese archivo, pero nunca lo haga antes de una#include
declaración. En cuanto a las funciones de plantilla definidas en los encabezados, desafortunadamente no conozco una buena solución que no sea simplemente escribir el espacio de nombres ... Quizás podría poner unausing
declaración dentro de un alcance separado{ /* using statement in between brackets */ }
, que al menos evitaría que escape del archivo actual .Elemento 59 en Sutter y Alexandrescu "Estándares de codificación C ++: 101 reglas, directrices y mejores prácticas" :
Un archivo de encabezado es un invitado en uno o más archivos de origen. Un archivo de encabezado que incluye
using
directivas y declaraciones también trae a sus amigos ruidosos.Una
using
declaración trae a un amigo. Unausing
directiva trae a todos los amigos en el espacio de nombres. El uso de sus profesores deusing namespace std;
es una directiva using.Más en serio, tenemos espacios de nombres para evitar conflictos de nombres. Un archivo de encabezado está destinado a proporcionar una interfaz. La mayoría de los encabezados son independientes de qué código puede incluirlos, ahora o en el futuro. Agregar
using
declaraciones para conveniencia interna dentro del encabezado coloca esos nombres convenientes en todos los clientes potenciales de ese encabezado. Eso puede llevar a un conflicto de nombres. Y es simplemente de mala educación.fuente
Debe tener cuidado al incluir encabezados dentro de los encabezados. En proyectos grandes, puede crear una cadena de dependencia muy enredada que desencadena reconstrucciones más grandes / más largas de las que realmente eran necesarias. Consulte este artículo y su seguimiento para obtener más información 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 use la declaración de avance siempre que pueda (cuando la clase sea necesaria es un puntero o una referencia).
En cuanto a los espacios de nombres, tiendo a usar el ámbito explícito del espacio de nombres en mis archivos de encabezado, y solo pongo un
using namespace
en mis archivos cpp.fuente
template
declaración de funciones? eso tiene que ocurrir en el encabezado, ¿no?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 de SO:
El estándar de codificación GSFC C ++ dice:
La primera de las preguntas con referencias cruzadas ahora incluye una cita del estándar de codificación GSFC C, y la justificación, pero la sustancia termina siendo la misma.
fuente
Tienes razón
using namespace
en que en la cabecera es peligroso. No sé cómo deshacerlo. Es fácil de detectar, sin embargo, solo busqueusing 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 incluya, más rápido se compilará. Eso ahorra tiempo a todos. Sin embargo, si el archivo de encabezado asume que algo debe incluirse antes, entonces debe incluirlo él mismo. De lo contrario, hace que los encabezados no sean independientes.
fuente
Tienes razón. Y cualquier archivo solo debe incluir los encabezados necesarios para ese archivo. En cuanto a "¿es común hacer las cosas mal en los proyectos del mundo real?" - ¡Oh si!
fuente
Como todas las cosas en la programación, el pragmatismo debería vencer al dogmatismo, en mi opinión.
Siempre que tome la decisión en todo el proyecto ("Nuestro proyecto usa STL extensamente y no queremos tener que anteponer todo con std ::."), No veo el problema con eso. Después de todo, lo único que corre el riesgo son las colisiones de nombres, 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 archivo de encabezado (no privado), puedo ver cómo generaría confusión entre el equipo y debería evitarse.
fuente
Con respecto a "¿Hay alguna forma de deshacer [una
using
declaración]?"Creo que es útil señalar que las
using
declaraciones se ven afectadas por el alcance.Así que efectivamente sí. Al limitar el alcance de la
using
declaración, su efecto solo dura dentro de ese alcance; se 'deshace' cuando termina ese alcance.Cuando la
using
declaración 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 encabezado, si la
using
declaración está en el alcance del archivo, esto se extenderá al alcance de cualquier archivo en el que esté incluido el encabezado.fuente
namespace
declaración) frente a cómo funciona realmente (como una variable).{}
encerrarlo limita su alcance,{}
después de que no hace nada relacionado con él. Esa es una forma accidental en la queusing namespace
se aplica globalmente.Creo que puede usar 'using' en los encabezados de C ++ de manera segura si escribe sus declaraciones en un espacio de nombres anidado como este:
Esto debe 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.
fuente
using
declaraciones dentro de las definiciones de funciones donde puedo para que no contaminen los espacios de nombres fuera de la función. Pero ahora quiero usar literales definidos por el usuario de C ++ 11 en un archivo de encabezado, y según la convención habitual, los operadores literales están protegidos por un espacio de nombres; pero no quiero usarlos en listas de inicializadores de constructores que no están en un alcance en el que puedo usar unausing
declaración no contaminante . Entonces esto es genial para resolver ese problema.error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
. Al menos, eso es lo que me está sucediendo en g ++.