Parece haver diferentes visões sobre o uso de 'using' em relação ao namespace std.
Alguns dizem usar ' using namespace std
', outros dizem que não, mas prefixam funções std que devem ser usadas com ' std::
', enquanto outros dizem que use algo assim:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
para todas as funções std que devem ser usadas.
Quais são os prós e os contras de cada um?
c++
namespaces
paoloricardo
fonte
fonte
Respostas:
A maioria dos usuários de C ++ gosta de ler
std::string
,std::vector
etc. Na verdade, ver um rawvector
me faz pensar se este é ostd::vector
ou um diferente definido pelo usuáriovector
.Eu sempre sou contra usar
using namespace std;
. Ele importa todos os tipos de nomes para o namespace global e pode causar todos os tipos de ambigüidades não óbvias.Aqui estão alguns identificadores comuns que estão no
std
namespace: contagem, classificação, localização, igual, reverso. Ter uma variável local chamadacount
significa queusing namespace std
não permitirá que você use emcount
vez destd::count
.O exemplo clássico de um conflito de nome indesejado é algo como o seguinte. Imagine que você é um iniciante e não conhece
std::count
. Imagine que você está usando algo diferente<algorithm>
ou que foi puxado por um cabeçalho aparentemente não relacionado.O erro costuma ser longo e hostil porque
std::count
é um modelo com alguns tipos aninhados longos.Isso está OK, porque
std::count
vai para o namespace global e a contagem de função o oculta.Talvez um pouco surpreendentemente, isso está OK. Os identificadores importados para um escopo declarativo aparecem no namespace comum que inclui tanto onde são definidos quanto para onde são importados. Em outras palavras,
std::count
é visível comocount
no namespace global, mas apenas dentroincrement
.E por razões semelhantes,
count
é ambíguo aqui.using namespace std
não causastd::count
, esconda o exteriorcount
como seria de esperar. Ausing namespace
regra significa questd::count
parece (naincrement
função) como se tivesse sido declarada no escopo global, ou seja, no mesmo escopoint count = 0;
e, portanto, causando a ambigüidade.fonte
using std::xxx;
. Ele não polui o espaço de nomes, escrever código será mais curto e acho quecopy
é muito mais legível do questd::copy
.Excluindo o básico (ter que adicionar std :: na frente de todos os objetos / funções stl e menos chance de conflito se você não tiver 'using namespace std')
Também é importante notar que você nunca deve colocar
Em um arquivo de cabeçalho, pois ele pode se propagar para todos os arquivos que incluem esse arquivo de cabeçalho, mesmo se eles não quiserem usar esse namespace.
Em alguns casos, é muito benéfico usar coisas como
Como se houvesse uma versão especializada de swap, o compilador irá usá-la, caso contrário, ele voltará a
std::swap
.Se você ligar
std::swap
, você sempre usará a versão básica, que não chamará a versão otimizada (se houver).fonte
using std::swap
(que é a única coisa que eu sempre uso).u n s
pode se propagar. Apenas para observar que ele também pode se infiltrar em cabeçalhos construídos corretamente: Eles apenas precisam ser incluídos após um cabeçalho desonesto.swap
oumove
(ouhash
,less
etc.), você deve colocar essa especialização denamespace std
qualquer maneira. Por exemplo:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
Primeiro, algumas terminologias:
using std::vector;
using namespace std;
Acho que usar as diretivas de uso é bom, desde que não sejam usadas no escopo global em um arquivo de cabeçalho. Então tendo
no seu arquivo .cpp não é realmente um problema e, se for o caso, está completamente sob seu controle (e pode até mesmo ter como escopo blocos específicos, se desejado). Não vejo nenhuma razão particular para confundir o código com uma série de
std::
qualificadores - torna-se apenas um monte de ruído visual. No entanto, se você não estiver usando um monte de nomes dostd
namespace em seu código, também não vejo problema em a diretiva. É uma tautologia - se a diretiva não for necessária, não há necessidade de usá-la.Da mesma forma, se você pode sobreviver com algumas declarações de uso (em vez de diretivas de uso ) para tipos específicos no
std
namespace, então não há razão para que você não deva ter apenas esses nomes específicos trazidos para o namespace atual. Da mesma forma, acho que seria uma loucura e um aborrecimento contábil ter 25 ou 30 declarações de uso quando uma única diretiva de uso faria o mesmo bem.Também é bom ter em mente que há momentos em que você deve usar uma declaração de uso. Consulte o "Item 25: Considere o suporte para uma troca sem lançamento" de Scott Meyers em Effective C ++, Third Edition. Para que uma função genérica e modelada use o 'melhor' método de troca para um tipo parametrizado, você precisa fazer uso de uma declaração de uso e pesquisa dependente de argumento (também conhecida como pesquisa ADL ou Koenig):
Acho que devemos olhar para os idiomas comuns para várias linguagens que fazem uso significativo de namespaces. Por exemplo, Java e C # usam namespaces em grande medida (possivelmente mais do que C ++). A forma mais comum pela qual os nomes dentro de namespaces são usados nessas linguagens é trazendo-os para o escopo atual em massa com o equivalente a uma diretiva using. Isso não causa problemas generalizados e, nas poucas vezes em que é um problema, é tratado como uma 'exceção', lidando com os nomes em questão por meio de nomes totalmente qualificados ou por aliasing - exatamente como pode ser feito em C ++.
Herb Sutter e Andrei Alexandrescu têm a dizer isso no "Item 59: Não escreva usos de namespace em um arquivo de cabeçalho ou antes de um #include" de seu livro, Padrões de Codificação C ++: 101 Regras, Diretrizes e Melhores Práticas:
Stroupstrup é frequentemente citado como dizendo, "Não polua o namespace global", em "The C ++ Programming Language, Third Edition". Ele de fato diz isso (C.14 [15]), mas se refere ao capítulo C.10.1 onde diz:
E como alguém tem a mesma vantagem de um 'usuário preguiçoso de nomes globais'? Tirando vantagem da diretiva using, que disponibiliza com segurança os nomes em um namespace para o escopo atual.
Observe que há uma distinção - nomes no
std
namespace disponibilizados para um escopo com o uso adequado de uma diretiva using (colocando a diretiva após o#includes
) não poluem o namespace global. É apenas disponibilizar esses nomes facilmente e com proteção contínua contra confrontos.fonte
std::
qualificadores não bagunçam o código - há outras maneiras de evitar isso (using-declarations ou typedefs geralmente resolvem).using namespace std;
diretiva " " não o impede de declarar seu identificador natural 'list
' - é só que se você o fizer, você não pode use maisstd::list
sem qualificá-lo. Isso não é diferente de se não houver umausing namespace std;
diretiva " ". Ou eu estou esquecendo de alguma coisa?Nunca use o uso de namespace no escopo global em um arquivo de cabeçalho. Isso pode levar a conflitos e o responsável pelo arquivo onde o conflito aparece não tem controle sobre a causa.
No arquivo de implementação, as escolhas são muito menos adequadas.
Colocar um usando namespace std traz todos os símbolos desses namespaces. Isso pode ser problemático, pois quase nenhum corpo conhece todos os símbolos que estão lá (portanto, ter uma política de nenhum conflito é impossível de aplicar na prática) sem falar dos símbolos que serão adicionados. E o padrão C ++ permite que um cabeçalho adicione símbolos de outros cabeçalhos (o padrão C não permite isso). Ainda pode funcionar bem na prática para simplificar a escrita em caso controlado. E se ocorrer um erro, ele será detectado no arquivo que apresenta o problema.
Colocando usando std :: name; tem a vantagem da simplicidade de escrita sem o risco de importar símbolos desconhecidos. O custo é que você precisa importar explicitamente todos os símbolos desejados.
Qualificar explicitamente adiciona um pouco de confusão, mas acho que é menos problemático alguma prática.
No meu projeto, uso qualificação explícita para todos os nomes, aceito usar std :: name, luto contra o uso de namespace std (temos um interpretador lisp que tem seu próprio tipo de lista e, portanto, o conflito é uma coisa certa).
Para outros namespaces, você também deve levar em consideração as convenções de nomenclatura usadas. Eu sei de um projeto que usa namespace (para controle de versão) e prefixo em nomes. Fazer um
using namespace X
then é quase sem risco e não fazer isso leva a um código de aparência estúpidaPrefixNS::pfxMyFunction(...)
.Existem alguns casos em que você deseja importar os símbolos. std :: swap é o caso mais comum: você importa std :: swap e então usa swap não qualificado. A pesquisa dependente do argumento encontrará uma troca adequada no namespace do tipo, se houver, e retornará ao modelo padrão, se não houver.
Editar:
Nos comentários, Michael Burr questiona se os conflitos ocorrem no mundo real. Aqui está um exemplo real ao vivo. Temos uma linguagem de extensão com um dialeto lisp. Nosso intérprete tem um arquivo de inclusão, lisp.h contendo
Tivemos que integrar e adaptar algum código (que chamarei de "motor") que se parecia com isto:
Então, nós modificamos assim:
Boa. Tudo funciona. Alguns meses depois, "module.h" foi modificado para incluir "list.h". Os testes foram aprovados. "módulo" não foi modificado de uma forma que afetou sua ABI, então a biblioteca "engine" poderia ser usada sem recompilar seus usuários. Os testes de integração correram bem. Novo "módulo" publicado. A próxima compilação do motor quebrou quando seu código não foi modificado.
fonte
Se você não corre o risco de conflitos de nome em seu código com std e outras bibliotecas, você pode usar:
Mas se você quiser saber exatamente a dependência do seu código para documentação ou se houver risco de conflitos de nome, use o outro caminho:
A terceira solução, não use essas soluções e escreva std :: antes de cada uso no código traz mais segurança, mas talvez um pouco mais pesado no código ...
fonte
Ambos
e
adicione alguns símbolos (um ou muitos) ao namespace global. E adicionar símbolos ao namespace global é algo que você nunca deve fazer em arquivos de cabeçalho. Você não tem controle sobre quem incluirá seu cabeçalho. Existem muitos cabeçalhos que incluem outros cabeçalhos (e cabeçalhos que incluem cabeçalhos que incluem cabeçalhos e assim por diante ...).
Nos arquivos de implementação (.cpp) depende de você (lembre-se de fazê-lo somente após todas as diretivas #include). Você pode quebrar apenas o código neste arquivo específico, por isso é mais fácil de gerenciar e descobrir o motivo do conflito de nomes. Se você preferir usar std :: (ou qualquer outro prefixo, pode haver muitos namespaces em seu projeto) antes de identificadores, está tudo bem. Se você gosta de adicionar identificadores que usa ao namespace global, tudo bem. Se você quiser colocar todo o namespace em sua cabeça :-), é com você. Embora os efeitos sejam limitados a uma única unidade de compilação, é aceitável.
fonte
Para mim, prefiro usar
::
quando possível.Eu odeio escrever:
Com sorte, com C ++ 0x eu escreveria isto:
Se o namespace for muito longo,
fonte
++i
, nãoi++
porque, se for definido, crie uma cópia temporária desnecessária do iterador.Você nunca deve estar
using namespace std
no escopo do namespace em um cabeçalho. Além disso, suponho que a maioria dos programadores se perguntará quando verãovector
oustring
nãostd::
, então acho que nãousing namespace std
é melhor. Portanto, eu argumento para nunca serusing namespace std
.Se você sentir que deve, adicione local usando declarações como
using std::vector
. Mas pergunte-se: de que vale isso? Uma linha de código é escrita uma vez (talvez duas vezes), mas é lida dez, cem ou mil vezes. O esforço de digitação economizado ao adicionar uma declaração ou diretiva de uso é marginal em comparação com o esforço de ler o código.Com isso em mente, em um projeto de dez anos atrás, decidimos qualificar explicitamente todos os identificadores com seus nomes de namespace completos. O que parecia estranho a princípio se tornou rotina em duas semanas. Agora, em todos os projetos de toda aquela empresa ninguém está mais usando diretivas ou declarações. (Com uma exceção, veja abaixo.) Olhando para o código (vários MLoC) depois de dez anos, sinto que tomamos a decisão certa.
Eu descobri que normalmente, aqueles que se opõem ao banimento
using
geralmente não tentaram para um projeto. Aqueles que tentaram, muitas vezes acham melhor do que usar diretivas / declarações depois de um tempo muito curto.Nota: A única exceção é a
using std::swap
necessária (especialmente em código genérico) para coletar sobrecargas deswap()
que não podem ser colocadas nostd
namespace (porque não temos permissão para colocar sobrecargas destd
funções neste namespace).fonte
std
, mas não sobrecarregar. Desculpe por aquele cérebro. Vou corrigir a postagem.using namespace
diretiva era fazer digitação ; ao contrário, era para facilitar a leitura , porque, como você diz, esse código terá de ser lido dezenas, centenas ou milhares de vezes. E, para algumas pessoas, é muito mais fácil de ler com menosstd::
confusão. Mas isso provavelmente se resume à habilidade pessoal de percepção; algumas pessoas filtramstd::
ou até mesmo precisam dela para orientação (como serifas), outras tropeçam nela e se sentem em uma estrada esburacada.Os namespaces mantêm o código contido para evitar confusão e poluição das assinaturas de função.
Aqui está uma demonstração completa e documentada do uso adequado de namespace :
Resultado:
fonte
using namespace std
importa o conteúdo dostd
namespace para o atual. Portanto, a vantagem é que você não terá que digitarstd::
antes de todas as funções desse namespace. No entanto, pode acontecer que você tenha namespaces diferentes com funções com o mesmo nome. Assim, você pode acabar não ligando para quem deseja.Especificar manualmente quais você deseja importar
std
evita que isso aconteça, mas pode resultar em uma longa lista de uso no início de seu arquivo, o que alguns desenvolvedores vão achar feio;)!Pessoalmente, prefiro especificar o namespace cada vez que uso uma função, exceto quando o namespace é muito longo; nesse caso, coloco algum using no início do arquivo.
EDITAR: conforme observado em outra resposta, você nunca deve colocar um
using namespace
em um arquivo de cabeçalho, pois ele se propagará para todos os arquivos incluindo este cabeçalho e, portanto, pode produzir um comportamento indesejado.EDIT2: corrigiu minha resposta, graças ao comentário de Charles.
fonte
using namespace std;
importa o conteúdo dostd
namespace para o namespace global. Isso não muda o namespace padrão. Definir algo no namespace global após umusing namespace std
não irá colocá-lo magicamente nostd
namespace.Muito parecido com Java, onde você pode usar, pode incluir java.util. * Ou simplesmente selecionar cada classe individualmente, isso depende do estilo. Observe que você não quer um
using namespace std
no início de seu arquivo / escopo amplo porque poluirá o namespace e possivelmente terá conflitos, anulando o ponto de namespaces. Mas se você tem uma função que usa muito STL, ela bagunça o código para ter uma confusão de sintaxe de prefixação em sua lógica e você provavelmente deve considerar o usousing namespace std
(ao usar uma variedade de classes) ouusing
s individuais (ao usar alguns aulas frequentemente).fonte
Esta discussão estará viva enquanto o IDE com o qual você trabalha não for flexível o suficiente para mostrar ou ocultar as informações exatas de que você precisa.
Isso ocorre porque a aparência do seu código depende da tarefa em questão.
Ao criar meu código-fonte, prefiro ver exatamente qual classe estou usando: é
std::string
ou aBuzFlox::Obs::string
classe?Ao projetar o fluxo de controle, nem mesmo estou interessado nos tipos de variáveis, mas quero me concentrar em
if
'sewhile
' econtinue
's.Portanto, este é o meu conselho:
Dependendo do público de seu código e do poder de suas ferramentas, escolha a forma que lê mais facilmente ou fornece mais informações.
fonte
Existem várias maneiras de consertar isso.
Primeiro: use como você fez.
Segundo: fazer
namespace S = std;
, reduzindo 2 caracteres.Terceiro: use
static
.Quarto: não use nomes que
std
usa.fonte
A única razão para deixar de fora o std :: é que você poderia, em teoria, reimplementar todas as funções STL por conta própria. Então, suas funções podem ser trocadas de std :: vector para my :: vector sem alterar o código.
fonte
Por que não por exemplo
em vez do pesado
Acho isso muito mais legível e é meu padrão para codificação.
Você pode até mesmo usá-lo para incluir algumas informações semânticas para o leitor. Por exemplo, considere os protótipos de função
quais são o valor de retorno?
Que tal ao invés
fonte