Em todos os nossos cursos C ++, todos os professores sempre colocam using namespace std;
logo após os #include
s em seus .h
arquivos. Isso me parece perigoso desde então, ao incluir aquele cabeçalho em outro programa, irei obter o namespace importado para o meu programa, talvez sem perceber, pretender ou desejar (a inclusão do cabeçalho pode ser profundamente aninhada).
Portanto, minha pergunta é dupla: Estou certo de que using namespace
não deve ser usado em arquivos de cabeçalho e / ou há alguma maneira de desfazê-lo, algo como:
//header.h
using namespace std {
.
.
.
}
Mais uma pergunta na mesma linha: um arquivo de cabeçalho deve conter #include
todos os cabeçalhos de que seu .cpp
arquivo correspondente precisa, apenas aqueles que são necessários para as definições de cabeçalho e deixar o resto do .cpp
arquivo #include
, ou nenhum e declarar tudo o que precisa extern
?
O raciocínio por trás da pergunta é o mesmo acima: Não quero surpresas ao incluir .h
arquivos.
Além disso, se eu estiver certo, isso é um erro comum? Quero dizer, na programação do mundo real e em projetos "reais" por aí.
Obrigado.
fonte
using namespace
declarações, poderá usar o nome totalmente qualificado para resolver o problema.Respostas:
Definitivamente, você NÃO deve usar
using namespace
em cabeçalhos precisamente pelo motivo que disse, que pode alterar inesperadamente o significado do código em qualquer outro arquivo que inclua esse cabeçalho. Não há como desfazer um, ousing namespace
que é outro motivo pelo qual é tão perigoso. Normalmente, apenas usogrep
ou algo semelhante para ter certeza de queusing namespace
não está sendo mencionado nos cabeçalhos, em vez de tentar algo mais complicado. Provavelmente verificadores de código estático sinalizam isso também.O cabeçalho deve incluir apenas os cabeçalhos que ele precisa para compilar. Uma maneira fácil de impor isso é sempre incluir o cabeçalho do próprio arquivo de origem como a primeira coisa, antes de quaisquer outros cabeçalhos. Então, o arquivo de origem não será compilado se o cabeçalho não for independente. Em alguns casos, por exemplo, referindo-se a classes de detalhes de implementação em uma biblioteca, você pode usar declarações de encaminhamento em vez de
#include
porque você tem controle total sobre a definição de tal classe declarada de encaminhamento.Não tenho certeza se chamaria de comum, mas definitivamente aparece de vez em quando, geralmente escrito por novos programadores que não estão cientes das consequências negativas. Normalmente, apenas um pouco de educação sobre os riscos resolve todos os problemas, pois é relativamente simples de corrigir.
fonte
using
declarações em nossos.cpp
arquivos? os3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
s são a morte na ponta dos dedos.template
funções - que deveriam estar nos cabeçalhos?typedefs
?using
declarações dentro de.cpp
arquivos sem muita preocupação porque o escopo será limitado apenas a esse arquivo, mas nunca faça isso antes de uma#include
declaração. Quanto às funções de modelo definidas em cabeçalhos, infelizmente não conheço uma boa solução além de apenas escrever o namespace ... Talvez você pudesse colocar umausing
declaração dentro de um escopo separado{ /* using statement in between brackets */ }
, que pelo menos impediria de escapar do arquivo atual .Item 59 nos "Padrões de codificação C ++: 101 regras, diretrizes e melhores práticas" de Sutter e Alexandrescu :
Um arquivo de cabeçalho é um convidado em um ou mais arquivos de origem. Um arquivo de cabeçalho que inclui
using
diretivas e declarações atrai seus amigos desordeiros também.Uma
using
declaração traz um amigo. Umausing
diretiva traz todos os amigos no namespace. O uso de seus professoresusing namespace std;
é uma diretiva de uso.Mais a sério, temos namespaces para evitar conflito de nomes. Um arquivo de cabeçalho destina-se a fornecer uma interface. A maioria dos cabeçalhos é independente de qual código pode incluí-los, agora ou no futuro. Adicionar
using
instruções para conveniência interna no cabeçalho impõe esses nomes convenientes a todos os clientes potenciais desse cabeçalho. Isso pode levar a conflito de nomes. E é simplesmente rude.fonte
Você precisa ter cuidado ao incluir cabeçalhos dentro de cabeçalhos. Em grandes projetos, ele pode criar uma cadeia de dependências muito emaranhada que dispara reconstruções maiores / mais longas do que o realmente necessário. Confira este artigo e seu acompanhamento para aprender mais sobre a importância de uma boa estrutura física em projetos C ++.
Você só deve incluir cabeçalhos dentro de um cabeçalho quando absolutamente necessário (sempre que a definição completa de uma classe for necessária) e usar a declaração de encaminhamento sempre que puder (quando a classe necessária for um ponteiro ou uma referência).
Quanto aos namespaces, tendo a usar o escopo de namespace explícito em meus arquivos de cabeçalho e apenas coloco um
using namespace
em meus arquivos cpp.fonte
template
declaração de função? isso tem que ocorrer no cabeçalho, não?Verifique os padrões de codificação do Goddard Space Flight Center (para C e C ++). Isso acabou sendo um pouco mais difícil do que costumava ser - veja as respostas atualizadas para as perguntas do SO:
O padrão de codificação GSFC C ++ diz:
A primeira das perguntas com referência cruzada agora inclui uma citação do padrão de codificação GSFC C e a justificativa, mas a substância acaba sendo a mesma.
fonte
Você está certo que o
using namespace
cabeçalho é perigoso. Não sei como desfazer isso. É fácil detectá-lo, porém, basta pesquisarusing namespace
nos arquivos de cabeçalho. Por esse último motivo, é incomum em projetos reais. Colegas de trabalho mais experientes logo reclamarão se alguém fizer algo parecido.Em projetos reais, as pessoas tentam minimizar a quantidade de arquivos incluídos, porque quanto menos você incluir, mais rápido será a compilação. Isso economiza o tempo de todos. No entanto, se o arquivo de cabeçalho presume que algo deve ser incluído antes dele, ele deve incluí-lo. Caso contrário, torna os cabeçalhos não independentes.
fonte
Você está certo. E qualquer arquivo deve incluir apenas os cabeçalhos necessários para esse arquivo. Quanto a "fazer coisas erradas é comum em projetos do mundo real?" - Ai sim!
fonte
Como todas as coisas na programação, o pragmatismo deve vencer o dogmatismo, IMO.
Contanto que você tome a decisão em todo o projeto ("Nosso projeto usa STL extensivamente e não queremos ter que preceder tudo com std ::."), Não vejo problema nisso. Afinal, a única coisa que você está arriscando são as colisões de nomes, e com a onipresença da STL, é improvável que seja um problema.
Por outro lado, se foi uma decisão de um desenvolvedor em um único arquivo de cabeçalho (não privado), posso ver como isso geraria confusão entre a equipe e deveria ser evitado.
fonte
Com relação a "Existe alguma maneira de desfazer [uma
using
declaração]?"Acho que é útil salientar que as
using
declarações são afetadas pelo escopo.Então, efetivamente, sim. Ao limitar o âmbito da
using
declaração, o seu efeito só perdura nesse âmbito; é 'desfeito' quando esse escopo termina.Quando a
using
declaração é declarada em um arquivo fora de qualquer outro escopo, ela possui o escopo do arquivo e afeta tudo naquele arquivo.No caso de um arquivo de cabeçalho, se a
using
declaração estiver no escopo do arquivo, ela se estenderá ao escopo de qualquer arquivo no qual o cabeçalho esteja incluído.fonte
namespace
material de declaração) versus como ele realmente funciona (como uma variável).{}
envolvê-lo limita seu escopo,{}
depois de não fazer nada relacionado a ele. Essa é uma forma acidental deusing namespace
ser aplicada globalmente.Eu acredito que você pode usar 'using' em cabeçalhos C ++ com segurança se você escrever suas declarações em um namespace aninhado como este:
Isso deve incluir apenas as coisas declaradas em 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' sem os namespaces usados. Eu testei no compilador mingw64.
fonte
using
declarações dentro das definições de função onde posso para que não poluam os namespaces fora da função. Mas agora quero usar literais definidos pelo usuário C ++ 11 em um arquivo de cabeçalho e, pela convenção usual, os operadores literais são protegidos por um namespace; mas eu não quero usá-los em listas de inicializadores de construtor que não estão em um escopo que eu possa usar umausing
declaração não poluente . Portanto, isso é ótimo para resolver esse problema.error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
. Pelo menos, é isso que está acontecendo comigo no g ++.