Usando o namespace std

Parece haver visões diferentes sobre o uso de ‘using’ em relação ao namespace std.

Alguns dizem usar ‘ using namespace std ‘, outros dizem que não, mas prefixo funções std que devem ser usadas com ‘ std:: ‘, enquanto outros dizem usar algo como isto:

 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 contras de cada um? |

A maioria dos usuários de C ++ está muito feliz lendo std::string , std::vector , etc. Na verdade, ver um vector bruto me faz pensar se esse é o std::vector ou um vector definido pelo usuário diferente.

Eu sou sempre contra o 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 namespace std : count, sort, find, equal, reverse. Ter uma variável local chamada count significa que using namespace std não permitirá que você use count vez de std::count .

O exemplo clássico de um conflito de nome indesejado é algo como o seguinte. Imagine que você é um iniciante e não sabe sobre std::count . Imagine que você esteja usando outra coisa em ou tenha sido puxado por um header aparentemente não relacionado.

 #include  using namespace std; int count = 0; int increment() { return ++count; // error, identifier count is ambiguous } 

O erro é normalmente longo e hostil porque std::count é um modelo com alguns tipos nesteds longos.

Está tudo bem, porque std::count entra no namespace global e a contagem de funções o oculta.

 #include  using namespace std; int increment() { static int count = 0; return ++count; } 

Talvez um pouco surpreendentemente, tudo bem. Os identificadores importados em um escopo declarativo aparecem no namespace comum que inclui tanto o local onde eles são definidos e onde são importados. Em outras palavras, std::count é visível como count no namespace global, mas somente dentro do increment .

 #include  int increment() { using namespace std; static int count = 0; return ++count; } 

E por razões semelhantes, a count é ambígua aqui. using namespace std não causa std::count , oculta a count externa como seria de se esperar. A regra de using namespace significa que std::count parece (na function de increment ) como se fosse declarado no escopo global, isto é, no mesmo escopo de int count = 0; e, portanto, causando a ambiguidade.

 #include  int count = 0; int increment() { using namespace std; return ++count; // error ambiguous } 

Excluindo o básico (Tendo que adicionar std :: infront de todos os objects / 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

 using namespace std 

Em um arquivo de header, como ele pode se propagar para todos os arquivos que incluem esse arquivo de header, mesmo que eles não queiram usar esse namespace.

Em alguns casos, é muito benéfico usar coisas como

 using std::swap 

Como se houvesse uma versão especializada de swap, o compilador usaria isso, caso contrário ele retornará ao std :: swap

Se você chamar std :: swap, você sempre usará a versão básica, que não chamará a versão otimizada (se existir).

Primeiro, alguma terminologia:

  • using-declaration : using std::vector;
  • using-directive : using namespace std;

Eu acho que usando diretivas de uso são bem, contanto que eles não são usados ​​no escopo global em um arquivo de header. Então, tendo

 using namespace std; 

no seu arquivo .cpp não é realmente um problema, e se for, ele está completamente sob seu controle (e pode até mesmo ser definido para blocos específicos, se desejado). Não vejo nenhuma razão especial para confundir o código com uma série de std:: qualifiers – isso só se torna um monte de ruído visual. No entanto, se você não estiver usando um monte de nomes do namespace std em seu código, também não vejo nenhum problema em deixar de fora a diretiva. É uma tautologia – se a diretiva não é necessária, então não há necessidade de usá-la.

Da mesma forma, se você puder usar algumas declarações de uso (em vez de usar diretivas ) para tipos específicos no namespace std , então não há razão para você não ter apenas aqueles nomes específicos trazidos para o namespace atual. Da mesma forma, acho que seria uma loucura e um incômodo de contabilidade ter 25 ou 30 declarações de uso quando uma única diretiva de uso funcionasse da mesma maneira.

Também é bom ter em mente que há momentos em que você deve usar uma declaração de uso. Consulte o “Item 25: Considerar Suporte para uma Troca Não Jogável” de Scott Meyers, da C ++ Efetiva, Terceira Edição. Para ter uma function genérica e modelada, use o método de troca ‘melhor’ para um tipo com parâmetros, você precisa usar uma declaração dependente de utilização e declaração (também chamada de pesquisa ADL ou Koenig):

 template< typename T > void foo( T& x, T& y) { using std::swap; // makes std::swap available in this function // do stuff... swap( x, y); // will use a T-specific swap() if it exists, // otherwise will use std::swap() // ... } 

Eu 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 parte (possivelmente mais que C ++). Os nomes de caminhos mais comuns nos namespaces usados ​​nessas linguagens são trazendo-os para o escopo atual em massa com o equivalente de uma diretiva using. Isso não causa problemas generalizados, e as poucas vezes em que é um problema são tratadas em uma ‘exceção’, lidando com os nomes em questão através de nomes completos ou aliasing – assim como pode ser feito em C ++.

Herb Sutter e Andrei Alexandrescu têm isto a dizer no “Item 59: Não escreva usos de namespace em um arquivo de header ou antes de um #include” de seu livro, Padrões de Codificação C ++: 101 Regras, Diretrizes e Melhores Práticas:

Resumindo: Você pode e deve usar o namespace usando declarações e diretivas livremente em seus arquivos de implementação após as diretivas #include e se sentir bem com isso. Apesar das repetidas afirmações em contrário, o espaço de nomes que usa declarações e diretivas não é maligno e não derrota o propósito dos namespaces. Em vez disso, eles são o que tornam os namespaces utilizáveis.

Stroupstrup é frequentemente citado como “Não polua o namespace global”, em “A linguagem de programação C ++, terceira edição”. Ele de fato diz que (C.14 [15]), mas refere-se ao capítulo C.10.1 onde ele diz:

Uma declaração de uso adiciona um nome a um escopo local. Uma diretiva usando não; simplesmente torna os nomes acessíveis no escopo em que foram declarados. Por exemplo:

 namespaceX { int i , j , k ; } int k ; void f1() { int i = 0 ; using namespaceX ; // make names from X accessible i++; // local i j++; // X::j k++; // error: X::k or global k ? ::k ++; // the global k X::k ++; // X's k } void f2() { int i = 0 ; using X::i ; // error: i declared twice in f2() using X::j ; using X::k ; // hides global k i++; j++; // X::j k++; // X::k } 

Um nome declarado localmente (declarado por uma declaração comum ou por uma declaração de uso) oculta declarações não-locais com o mesmo nome e todas as sobrecargas ilegais do nome são detectadas no ponto de declaração.

Observe o erro de ambiguidade para k++ em f1() . Os nomes globais não recebem preferência sobre nomes de espaços de nomes tornados acessíveis no escopo global. Isso fornece proteção significativa contra conflitos acidentais de nomes e – o que é importante – garante que não haja vantagens a serem obtidas ao poluir o namespace global.

Quando as bibliotecas que declaram muitos nomes são disponibilizadas através de directivas de utilização, é uma vantagem significativa que os conflitos de nomes não utilizados não sejam considerados erros.

Espero ver uma redução radical no uso de nomes globais em novos programas usando namespaces em comparação com os programas tradicionais C e C ++. As regras para namespaces foram criadas especificamente para não oferecer vantagens a um usuário ” preguiçoso ” de nomes globais sobre alguém que toma cuidado para não poluir o escopo global.

E como alguém tem a mesma vantagem que um “usuário preguiçoso de nomes globais”? Aproveitando a diretiva using, que torna os nomes em um namespace com segurança disponíveis para o escopo atual.

Observe que há uma distinção – os nomes no namespace std 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 conflitos.

Nunca use o namespace no escopo global em um arquivo de header. Isso pode levar ao conflito e a pessoa encarregada do arquivo onde o conflito aparece não tem controle sobre a causa.

No arquivo de implementação, as opções são muito menos bem cortadas.

  • Colocar um namespace std usando traz todos os símbolos dos namespaces. Isso pode ser problemático, já que quase nenhum corpo conhece todos os símbolos que existem (assim, ter uma política de não 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 header adicione símbolos de outros headers (o C não permite isso). Ainda pode funcionar bem na prática para simplificar a escrita no 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 escrever sem o risco de importar símbolos desconhecidos. O custo é que você precisa importar explicitamente todos os símbolos desejados.

  • Qualificação explícita adiciona um pouco de confusão, mas acho que é menos problemático praticar.

No meu projeto, eu uso qualificação explícita para todos os nomes, aceito usar std :: name, eu luto contra o namespace std (nós temos um interpretador lisp que tem seu próprio tipo de lista e então o conflito é uma coisa certa).

Para outros namespaces, você também deve levar em conta as convenções de nomenclatura usadas. Eu sei de um projeto que usa namespace (para versionning) e prefixo em nomes. Fazer um using namespace X então, é quase sem risco e não fazê-lo leva a um código de aparência estúpido PrefixNS::pfxMyFunction(...) .

Existem alguns casos em que você deseja importar os símbolos. O std :: swap é o caso mais comum: você importa o std :: swap e depois usa o swap não qualificado. A pesquisa dependente de argumento encontrará uma troca adequada no namespace do tipo, se houver, e retornará ao modelo padrão, se não houver nenhum.


Editar:

Nos comentários, Michael Burr se pergunta se os conflitos ocorrem no mundo real. Aqui está um exemplo real ao vivo. Nós temos uma linguagem de extensão com um dialeto lisp. Nosso intérprete tem um arquivo de inclusão, lisp.h contendo

 typedef struct list {} list; 

Nós tivemos que integrar e adaptar algum código (que eu chamarei de “engine”), que ficou assim:

 #include  ... using std::list; ... void foo(list const&) {} 

Então nós modificamos assim:

 #include  #include "module.h" ... using std::list; ... void foo(list const&) {} 

Boa. Tudo funciona. Alguns meses depois, “module.h” foi modificado para include “list.h”. Os testes foram aprovados. O “módulo” não foi modificado de forma a afetar sua ABI, portanto, a biblioteca “engine” poderia ser usada sem recompilar seus usuários. Testes de integração foram OK. Novo “módulo” publicado. A próxima compilation do motor quebrou quando seu código não foi modificado.

Ambos

 using std::string; 

e

 using namespace std; 

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 header. Você não tem controle sobre quem includeá seu header, há muitos headers que incluem outros headers (e headers que incluem headers que incluem headers e assim por diante …).

Nos arquivos de implementação (.cpp) cabe a você (lembre-se de fazer isso depois de todas as diretivas #include). Você pode quebrar apenas o código neste arquivo específico, portanto, é mais fácil 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 dos indentificadores, tudo bem. Se você gosta de adicionar identificadores que usa ao namespace global, tudo bem. Se você quiser trazer todo o namespace em sua cabeça :-), cabe a você. Enquanto os efeitos são limitados a uma única unidade de compilation, é aceitável.

Se você não tiver um risco de conflito de nomes em seu código com std e outras bibliotecas, poderá usar:

 using namespace std; 

Mas se você quiser saber precisamente a dependência de seu código para documentação ou há um risco de conflitos de nome, use a outra maneira:

 using std::string; using std::cout; 

A terceira solução, não use essas soluções e escreva std :: antes que cada uso no código traga mais segurança, mas talvez um pouco de peso no código …

Para mim, prefiro usar :: quando possível.

 std::list iList; 

Eu odeio escrever:

 for(std::list::iterator i = iList.begin(); i != iList.end(); i++) { // } 

Espero que, com C ++ 0x, eu escreva isso:

 for(auto i = iList.begin(); i != iList.end(); i++) { // } 

Se o namespace for muito demorado,

 namespace dir = boost::filesystem; dir::directory_iterator file("e:/boost"); dir::directory_iterator end; for( ; file != end; file++) { if(dir::is_directory(*file)) std::cout < < *file << std::endl; } 

Você nunca deve estar using namespace std no escopo de namespace em um header. Além disso, suponho que a maioria dos programadores se perguntará quando virem vector ou string sem std:: , então acho que não using namespace std é melhor. Por isso eu argumento para nunca estar using namespace std em tudo.

Se você acha que precisa, adicione local usando declarações como using std::vector . Mas pergunte a si mesmo: o que é 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 salvo ao adicionar uma declaração ou diretiva usando é marginal comparado ao esforço de ler o código.

Com isso em mente, em um projeto há dez anos, decidimos qualificar explicitamente todos os identificadores com seus nomes completos de namespace. O que parecia estranho no começo se tornou rotina dentro de duas semanas. Agora, em todos os projetos de toda a empresa, ninguém usa mais 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 o experimentaram em 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 é using std::swap que é necessário (especialmente em código genérico) para pegar as sobrecargas do swap() que não podem ser colocadas no namespace std (porque não temos permissão para colocar sobrecargas de funções std para este namespace).

using namespace std importa o conteúdo do namespace std no atual. Assim, a vantagem é que você não terá que digitar std:: na frente de todas as funções desse namespace. No entanto, pode acontecer que você tenha namespaces diferentes que tenham funções com o mesmo nome. Assim, você pode acabar não chamando o que você quer.

Especificar manualmente quais você deseja importar no std impede que isso aconteça, mas pode resultar em uma longa lista de uso no início do seu arquivo, o que alguns desenvolvedores acharão feio;)!

Pessoalmente, eu prefiro especificar o namespace toda vez que eu uso uma function, exceto quando o namespace é muito longo, nesse caso eu coloco algumas usando no início do arquivo.

EDIT: como observado em outra resposta, você nunca deve colocar um using namespace em um arquivo de header, como ele irá se propagar para todos os arquivos, incluindo este header e, portanto, pode produzir um comportamento indesejado.

EDIT2: corrigido minha resposta, graças ao comentário de Charles.

Namespaces mantêm o código contido para evitar confusão e poluição de assinaturas de function.

Aqui está uma demonstração completa e documentada do uso adequado do namespace :

 #include  #include  // Uses ::log, which would be the log() here if it were not in a namespace, see https://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace // Silently overrides std::log //double log(double d) { return 420; } namespace uniquename { using namespace std; // So we don't have to waste space on std:: when not needed. double log(double d) { return 42; } int main() { cout < < "Our log: " << log(4.2) << endl; cout << "Standard log: " << std::log(4.2); return 0; } } // Global wrapper for our contained code. int main() { return uniquename::main(); } 

Saída:

 Our log: 42 Standard log: 1.43508 

Assim como em Java, onde você pode usar, pode include java.util. * Ou simplesmente selecionar cada class individualmente, isso depende do estilo. Note que você não quer um using namespace std no início do seu arquivo / escopo amplo porque você poluirá o namespace e possivelmente terá conflitos, derrotando o ponto de namespaces. Mas se você tem uma function que usa um monte de STL, ela bagunça o código para ter uma syntax de prefixos em sua lógica e você provavelmente deveria considerar using namespace std (ao usar uma variedade de classs) ou individual using s ( ao usar algumas classs com freqüência).

Essa discussão estará ativa desde que o IDE com o qual você trabalha não seja flexível o suficiente para mostrar ou ocultar as informações exatas de que você precisa.

Isso é porque o que você quer que seu código pareça depende da tarefa em mãos.

Ao criar meu código-fonte, prefiro ver exatamente qual class estou usando: std::string ou a BuzFlox::Obs::string ?

Ao projetar o stream de controle, eu nem estou interessado nos tipos de variables, mas quero um foco em if ‘s e while ‘s e continue ‘s.

Então, este é o meu conselho:

Dependendo do público do seu código e do poder de suas ferramentas, escolha a maneira mais fácil de ler ou que forneça mais informações.

Existem várias maneiras de corrigir isso.

Primeiro: use como o que você fez.

Segundo: faça namespace S = std; , reduzindo 2 chars.

Terceiro: use static .

Quarto: não use nomes que o std usa.

Quais são os prós e contras de cada

A única razão para deixar o std :: é que você poderia, em teoria, reimplementar todas as funções STL. Então suas funções podem ser trocadas de std :: vector para my :: vector sem alterar o código.

Por que não por exemplo

 typedef std::vector ints_t; ints_t ints1; .... ints_t ints2; 

em vez do desajeitado

 std::vector ints1; ... std::vector ints2; 

Acho isso muito mais legível e é o meu padrão para codificação.

Você pode até usá-lo para include algumas informações semânticas para o leitor. Por exemplo, considere os protótipos de function

 void getHistorgram(std::vector&, std::vector&); 

qual o valor de retorno?

Que tal em vez disso

 typedef std::vector values_t; typedef std::vector histogram_t; ... void getHistogram(values_t&, histogram_t&);