Por que "usar o namespace std;" considerada má prática?

2640

Outras pessoas me disseram que escrever using namespace std;código está errado e que eu deveria usá std::cout-lo std::cindiretamente.

Por que é using namespace std;considerada uma má prática? É ineficiente ou corre o risco de declarar variáveis ​​ambíguas (variáveis ​​que compartilham o mesmo nome que uma função no stdespaço para nome)? Isso afeta o desempenho?

akbiggs
fonte
512
Não esqueça que você pode fazer: "using std :: cout;" o que significa que você não precisa digitar std :: cout, mas não insere todo o espaço para nome std ao mesmo tempo.
Bill
2
O link nerd pago google-styleguide.googlecode.com/svn/trunk/… não funciona mais. Parece que o novo link é google.github.io/styleguide/cppguide.html#Other_C++_Features
MCG
64
É particularmente ruim usar 'using namespace std' no escopo do arquivo nos arquivos de cabeçalho. Usá-lo em arquivos de origem (* .cpp) no escopo do arquivo, afinal, não é tão ruim, pois seu efeito é limitado a uma única unidade de tradução. Ainda menos problemático é usá-lo dentro de funções ou classes, porque seu efeito é limitado ao escopo da função ou classe.
usar o seguinte
5
Eu iria desencorajar a usar usando directiva mas para namespaces específicos como std::literals::chrono_literals, Poco::Data:Keywords, Poco::Unitse outras coisas que vai lidar com literais ou truques de legibilidade. Sempre que estiver nos arquivos de cabeçalho ou implementação. Acho que pode ser bom em um escopo de função, mas, além de literais e outras coisas, não é útil.
Ludovic Zenohate Lagouardette
7
@ Jon: Não tem nada a ver com o namespace std em particular. Minha ênfase deveria estar em "no escopo do arquivo nos arquivos de cabeçalho". Para colocar isso como um conselho: Não use "using namespace" (std ou outro) no escopo do arquivo nos arquivos de cabeçalho. Não há problema em usá-lo em arquivos de implementação. Desculpe pela ambiguidade.
sh-

Respostas:

2230

Isso não está relacionado ao desempenho. Mas considere o seguinte: você está usando duas bibliotecas chamadas Foo e Bar:

using namespace foo;
using namespace bar;

Tudo funciona bem, e você pode ligar Blah()do Foo e Quux()do Bar sem problemas. Mas um dia você atualiza para uma nova versão do Foo 2.0, que agora oferece uma função chamada Quux(). Agora você tem um conflito: o Foo 2.0 e o Bar importam Quux()para o seu espaço de nomes global. Isso exigirá algum esforço para corrigir, especialmente se os parâmetros de função coincidirem.

Se você tivesse usado foo::Blah()e bar::Quux(), a introdução de foo::Quux()teria sido um não-evento.

Greg Hewgill
fonte
435
Eu sempre gostei de "importar big_honkin_name como bhn" do Python, então você pode simplesmente usar "bhn.something" em vez de "big_honkin_name.something" - realmente reduz a digitação. C ++ tem algo parecido?
paxdiablo
764
@Pax namespace io = boost :: sistema de arquivos;
AraK 21/09/09
152
Eu acho que é exagero dizer que é "algum esforço para consertar". Você não terá instâncias do novo foo :: Quux; portanto, desambigue todos os seus usos atuais com bar :: Quux.
MattyT 21/09/09
289
Alguém sensato criaria uma biblioteca com tipos cujo nome não qualificado colide com os tipos std?
erikkallen 21/09/09
94
@ TomA: O problema #defineé que ele não se restringe aos namespaces, mas atropela toda a base de código. Um alias de espaço para nome é o que você deseja.
sbi 25/09/09
1391

Concordo com tudo o que Greg escreveu , mas gostaria de acrescentar: pode até piorar do que Greg disse!

A Biblioteca Foo 2.0 pode introduzir uma função Quux(),, que é uma correspondência inequivocamente melhor para algumas de suas chamadas do Quux()que o bar::Quux()código chamado por anos. Então seu código ainda é compilado , mas silenciosamente chama a função errada e sabe o que é Deus. Isso é tão ruim quanto as coisas podem ficar.

Tenha em mente que o stdnamespace tem toneladas de identificadores, muitos dos quais são muito mais comuns (pense list, sort, string, iterator, etc.) que são muito propensos a aparecer em outro código, também.

Se você considera isso improvável: Houve uma pergunta feita aqui no Stack Overflow em que praticamente isso aconteceu (função incorreta chamada devido ao std::prefixo omitido ) cerca de meio ano depois de eu dar essa resposta. Aqui está outro exemplo mais recente dessa pergunta. Portanto, este é um problema real.


Aqui está mais um ponto de dados: muitos anos atrás, eu também costumava achar irritante ter que prefixar tudo da biblioteca padrão std::. Depois, trabalhei em um projeto no qual foi decidido desde o início que usingdiretivas e declarações são proibidas, exceto no escopo da função. Adivinha? A maioria de nós levou poucas semanas para se acostumar a escrever o prefixo e, depois de mais algumas semanas, a maioria de nós concordou que realmente tornava o código mais legível . Há uma razão para isso: se você gosta de uma prosa mais curta ou mais longa, é subjetivo, mas os prefixos objetivamente acrescentam clareza ao código. Não apenas o compilador, mas você também acha mais fácil ver a qual identificador é referido.

Em uma década, esse projeto cresceu para ter vários milhões de linhas de código. Como essas discussões surgem repetidas vezes, fiquei curioso com que freqüência o escopo da função (permitido) usingrealmente era usado no projeto. Encontrei as fontes e encontrei apenas uma ou duas dúzias de lugares onde era usado. Para mim, isso indica que, uma vez tentados, os desenvolvedores não acham std::doloroso o suficiente para empregar o uso de diretivas, mesmo uma vez a cada 100 kLoC, mesmo onde foi permitido o uso.


Conclusão: prefixar explicitamente tudo não causa nenhum mal, leva muito pouco tempo para se acostumar e possui vantagens objetivas. Em particular, torna o código mais fácil de interpretar pelo compilador e pelos leitores humanos - e esse provavelmente deve ser o objetivo principal ao escrever código.

sbi
fonte
140
Isso prejudica significativamente a densidade do código que você pode incluir em uma única linha. Você acaba escrevendo seu código de maneira muito extensa; o que reduz a legibilidade. Pessoalmente, acho que códigos mais curtos (mas não muito curtos) tendem a ser mais legíveis (já que há menos coisas para ler e menos coisas para se distrair).
Lie Ryan
92
Acho que você perdeu os velhos tempos antes de o C ++ ter uma stringaula padrão e, aparentemente, todas as bibliotecas tinham as suas. Diga a você: continuaremos escrevendo nosso código std::e você poderá executá- grep -v std:: | vimlo enquanto estiver navegando nele. Ou você pode ensinar ao seu editor que std::é uma palavra-chave que deve ser da mesma cor que a cor do plano de fundo. O que quer que funcione.
Mike DeSimone
80
Eu não acho que std::seja prejudicial. Ele carrega informações muito importantes (ou seja, "o que vier depois faz parte da biblioteca padrão", e ainda é um prefixo bastante curto e compacto. Na maioria das vezes, não há problema algum. Às vezes, você tem algumas linhas de código onde você precisa para se referir a símbolos específicos no stdnamespace muito, e, em seguida, um using. declaração em que resolve escopo específico o problema bem, mas no caso geral, não é ruído, que transmite informações valiosas , além de remoção de ambigüidades.
jalf
147
Sempre que vejo std::, sei que será std::sem ter que pensar sobre isso. Se eu ver stringou listou mappor si só, gostaria de saber um pouco.
Mateen Ulhaq
68
@LieRyan Então boa sorte escrevendo uma biblioteca de geometria sem nunca nomear algo vector, transformou distance. E esses são apenas exemplos dos muitos nomes muito comuns usados ​​na biblioteca padrão. Sugerir não usá-los por medo ou por uma opinião tendenciosa do recurso de namespace que é parte integrante do C ++ é bastante contraproducente.
Christian Rau
420

O problema de colocar using namespaceos arquivos de cabeçalho de suas classes é que ele força quem quiser usar suas classes (incluindo seus arquivos de cabeçalho) a estar 'usando' (ou seja, vendo tudo) esses outros espaços de nomes.

No entanto, você pode se sentir à vontade para colocar uma declaração de uso em seus arquivos * .cpp (privados).


Lembre-se de que algumas pessoas não concordam com o meu ditado "sinta-se à vontade" assim - porque, embora uma usingdeclaração em um arquivo cpp seja melhor que em um cabeçalho (porque não afeta as pessoas que incluem seu arquivo de cabeçalho), elas ainda não são bom (porque, dependendo do código, isso dificulta a manutenção da implementação da classe). Esta entrada Super FAQ do C ++ diz:

A diretiva using existe para o código C ++ legado e para facilitar a transição para os espaços para nome, mas você provavelmente não deve usá-lo regularmente, pelo menos não no seu novo código C ++.

O FAQ sugere duas alternativas:

  • Uma declaração de uso:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
  • Apenas digitando std ::

    std::cout << "Values:";
ChrisW
fonte
1
É claro que você também nunca deve assumir o estado do cout global, para que alguém não tenha std: cout << std :: hex e falhe em std :: restore_cout_state posteriormente. Mas isso é outro problema.
Moz
233

Recentemente, deparei com uma reclamação sobre o Visual Studio 2010 . Aconteceu que praticamente todos os arquivos de origem tinham essas duas linhas:

using namespace std;
using namespace boost;

Muitos recursos do Boost estão sendo incluídos no padrão C ++ 0x, e o Visual Studio 2010 possui muitos recursos C ++ 0x; portanto, de repente, esses programas não estavam sendo compilados.

Portanto, evitar using namespace X;é uma forma de proteger o futuro, uma maneira de garantir que uma alteração nas bibliotecas e / ou nos arquivos de cabeçalho em uso não interrompa um programa.

David Thornley
fonte
14
Este. Boost e std têm muita sobreposição - especialmente desde o C ++ 11.
einpoklum
1
Eu fiz isso uma vez e aprendi uma lição da maneira mais difícil. Agora, nunca uso usingfora de uma definição de função e raramente uso using namespace.
Ferruccio
210

Versão curta: não use usingdeclarações ou diretivas globais nos arquivos de cabeçalho. Sinta-se livre para usá-los em arquivos de implementação. Aqui está o que Herb Sutter e Andrei Alexandrescu têm a dizer sobre esse problema nos padrões de codificação C ++ (o destaque para a ênfase é minha):

Sumário

O uso do namespace é para sua conveniência, não para você infligir a outros: nunca escreva uma declaração de uso ou uma diretiva de uso antes de uma diretiva #include.

Corolário: nos arquivos de cabeçalho, não escreva no nível de namespace usando diretivas ou declarações; em vez disso, explicitamente qualifique o namespace para todos os nomes. (A segunda regra segue a primeira, porque os cabeçalhos nunca podem saber que outro cabeçalho #inclui pode aparecer depois deles.)

Discussão

Resumindo: você pode e deve usar o espaço para nome usando declarações e diretivas livremente em seus arquivos de implementação após #include diretivas e sinta-se bem com isso. Apesar de repetidas afirmações em contrário, o espaço para nome que usa declarações e diretivas não é ruim e não anula o objetivo dos espaços para nome. Em vez disso, são eles que tornam os namespaces utilizáveis .

mattnewport
fonte
4
Apenas mais uma opinião do programador aqui, mas, embora eu concorde 100% com a afirmação de que a palavra usingnunca deve aparecer em um cabeçalho, não estou tão convencido sobre a licença gratuita para colocar using namespace xyz;em qualquer lugar do seu código, especialmente se xyzestiver std. Eu uso o using std::vector;formulário, já que isso apenas puxa um único elemento do espaço para nome para o escopo pseudo-global, levando a muito menos risco de colisão.
dgnuff
2
Corridas @Lightness em Orbit, é claro que você tem direito à sua opinião. Teria sido mais útil se houvesse alguma tentativa de explicação por que você não concorda com os conselhos dados nesta resposta. Seria especialmente interessante entender qual é o sentido dos espaços para nome se 'usá-los' for ruim? Por que não apenas nomear as coisas std_cout em vez de std :: cout ... os criadores do C ++ / namespace devem ter tido alguma idéia quando se preocuparam em criá-las.
Nyholku
1
@nyholku: Não há necessidade - a maioria das outras respostas dá as mesmas razões que eu. Também não hesite em observar o ":)" Anexei ao meu comentário! E que eu não disse que os namespaces são ruins.
Lightness Races in Orbit
Sim, notei isso :) mas na OMI a maioria das respostas (que vão contra esse sábio conselho) são equivocadas (não que eu tenha feito estatísticas sobre a maioria agora). Se você concorda que o espaço para nome 'não é ruim', pode dizer onde acha que eles são adequados se você não concorda com esta resposta?
Nyholku
Eu não posso ajudar, mas sinto que o using namespacemal gotoé como o mal. Ambos têm usos válidos, mas 999 vezes em 1000 serão usados ​​incorretamente. Então, sim, using namespacena fonte você não poluirá o namespace de outras inclusões, puro. Mas ele ainda não o protegerá da "diversão" que surge de using namespace Foo+ using namespace Barcom você chamando (Foo implícito: :) baz(xyz)e de repente a quebra de código (sem alterações relacionadas) só porque Bar::baz()foi adicionada em algum lugar, o que simplesmente é melhor match (e, portanto, agora é chamado)
CharonX
122

Não se deve usar a usingdiretiva no escopo global, especialmente nos cabeçalhos. No entanto, há situações em que é apropriado, mesmo em um arquivo de cabeçalho:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; // No problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

Isso é melhor que a qualificação explícita ( std::sin, std::cos...), porque é mais curta e tem a capacidade de trabalhar com tipos de ponto flutuante definidos pelo usuário (por meio da pesquisa dependente de argumento (ADL)).

robson3.14
fonte
9
Sinto muito, mas discordo totalmente disso.
Billy ONeal
4
@ Billy: Não há outra maneira de suportar a chamada de userlib :: cos (userlib :: superint). Todo recurso tem um uso.
precisa
17
@Zan: Claro que existe. using std::cos;, using std::sin, Etc. A questão, porém, é que qualquer bem concebido userlibvai ter o seu sine cosdentro de seu próprio namespace, bem, então isso realmente não ajudá-lo. (A menos que haja um using namespace userlibantes deste modelo e isso seja tão ruim quanto using namespace std- e o escopo não seja limitado.) Além disso, a única função como essa que eu já vi acontecer é swape, nesses casos, eu recomendaria apenas a criação de um modelo especialização std::swape evitar todo o problema.
precisa
11
@BillyONeal: template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)(Não há nenhum modelo de função especialização parcial (FTPS), por isso às vezes você precisa de recorrer a uma sobrecarga em seu lugar.
SBI
38
@BillyONeal: Seu comentário (votado 7 vezes!) Está errado - a situação que você descreve é exatamente o que a ADL foi projetada para cobrir. Resumidamente, se xtiver um ou mais "namespaces associados" (por exemplo, se tiver sido definido em namespace userlib), qualquer chamada de função que se pareça cos(x)parecerá adicionalmente nesses namespaces - sem necessidadeusing namespace userlib; prévia de qualquer . Zan Lynx é certo (e C ++ pesquisa de nome é bizantino ...)
j_random_hacker
97

Não use globalmente

É considerado "ruim" somente quando usado globalmente . Porque:

  • Você desorganiza o espaço para nome em que está programando.
  • Os leitores terão dificuldade em ver de onde vem um identificador específico, quando você usa muitos using namespace xyz.
  • O que é verdadeiro para outros leitores do seu código-fonte é ainda mais verdadeiro para o leitor mais frequente: você mesmo. Volte em um ano ou dois e dê uma olhada ...
  • Se você apenas falar sobre using namespace stdvocê, pode não estar ciente de todas as coisas que captura - e quando adiciona outra #includeou muda para uma nova revisão de C ++, pode haver conflitos de nome dos quais não estava ciente.

Você pode usá-lo localmente

Vá em frente e use-o localmente (quase) livremente. Evidentemente, isso impede que você repitastd:: - e a repetição também é ruim.

Um idioma para usá-lo localmente

No C ++ 03, havia um idioma - código padrão - para implementar uma swapfunção para suas classes. Foi sugerido que você realmente usasse um local using namespace std- ou pelo menos using std::swap:

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

Isso faz a seguinte mágica:

  • O compilador escolherá o std::swapfor value_, ievoid std::swap(int, int) .
  • Se você estiver sobrecarregado void swap(Child&, Child&) implementada, o compilador a escolherá.
  • Se você não tiver essa sobrecarga, o compilador usará void std::swap(Child&,Child&)e tentará sua melhor troca.

Com o C ++ 11, não há mais razão para usar esse padrão. A implementação de std::swapfoi alterada para encontrar uma potencial sobrecarga e escolhê-la.

towi
fonte
5
"A implementação do std :: swap foi alterada para encontrar uma potencial sobrecarga e escolhê-la." - O que? Você tem certeza sobre isso? Embora seja verdade que fornecer um costume swapem primeiro lugar não seja mais tão importante no C ++ 11, já que o std::swappróprio é mais flexível (usa a semântica de movimentação). Mas std::swapescolher automaticamente sua própria troca personalizada, isso é absolutamente novo para mim (e eu realmente não acredito nisso).
Christian Rau
@ChristianRau Acho que sim. Eu li isso em algum lugar. Sempre podemos perguntar a Howard , ele deveria saber. Estou cavando e cavando agora ...
towi
14
Mesmo no caso de troca, o idioma mais claro (e felizmente mais comum) é escrever em using std::swap;vez de using namespace std;. O idioma mais específico tem menos efeitos colaterais e, portanto, torna o código mais sustentável.
Adrian McCarthy
11
A sentença final está errada. No C ++ 11, o Std Swap Two Step foi oficialmente abençoado como o caminho certo para ligar swap, e vários outros lugares no padrão foram alterados para dizer que eles chamam swapassim (NB, como mencionado acima, using std::swapé o caminho certo, não using namespace std). Mas std::swapele próprio não foi enfaticamente alterado para encontrar outro swape usá-lo. Se std::swapfor chamado, std::swapserá usado.
23615 Jonathan Wakely
3
using std::swapPorém, pode ser mais prudente digitar localmente, reduzir o espaço para nome local e, ao mesmo tempo, criar código de auto-documentação. Raramente você está interessado em todo o espaço para nome padrão, então escolha as partes que mais lhe interessam.
Lundin
79

Se você importar os arquivos de cabeçalho direito de repente você tem nomes como hex, left, plusou countno seu âmbito global. Isso pode ser surpreendente se você não souber que std::contém esses nomes. Se você também tentar usar esses nomes localmente, poderá causar certa confusão.

Se todo o material padrão estiver em seu próprio espaço para nome, você não precisa se preocupar com colisões de nomes com seu código ou outras bibliotecas.

sth
fonte
12
+1 para não mencionar distance. ainda prefiro nomes não qualificados sempre que possível, uma vez que isso aumenta a legibilidade para mim. além disso, acho que o fato de que geralmente não qualificamos as coisas no discurso oral e estamos dispostos a gastar tempo resolvendo possíveis ambiguidades, significa que tem valor ser capaz de entender o que se está falando sem qualificações e aplicado à fonte código que significa que está estruturado de forma a ficar claro o que é, mesmo sem qualificações.
Saúde e hth. #
Para ser justo, porém, você não tem a maioria deles, se não incluir <iomanip>. Ainda assim, bom argumento.
einpoklum
48

Outra razão é surpresa.

Se eu vejo cout << blah, em vez de std::cout << blahpensar: o que é isso cout? Isso é normal cout? É algo especial?

Martin Beckett
fonte
25
Isso é uma piada? Eu realmente não posso dizer. Se não, então eu pessoalmente diria que é o "cout" normal, a menos que você não confie no código, pois caso contrário isso seria um cheiro de código MUITO MAIOR, IMO. ... E se você não confia no código, por que está usando em primeiro lugar? Observe que não estou dizendo "CONFIE EM TODAS AS COISAS !!" mas isso também parece um pouco exagerado se você estiver, digamos, lidando com alguma biblioteca conhecida do GitHub ou algo assim.
Brent Rittenhouse
28
@BrentRittenhouse couté um mau exemplo, porque todos o reconhecem. Mas imagine futureem um aplicativo financeiro. É um contrato para comprar ou vender algo em uma data especificada? Não, não é. Se o código dissesse que std::futurevocê não seria tão facilmente confuso.
James Hollis
2
@BrentRittenhouse talvez seja um exemplo ruim, existem pelo menos quatro bibliotecas diferentes que têm cout. Pode ser "é uma biblioteca padrão? Libstdc ++? Stl? Outra coisa?" E não, nem todo mundo sabe std :: cout, pelo menos inerentemente, 6 dos 7 novos trabalhadores que recebemos não. Porque os currículos da educação não usam os da educação. Eu tenho que afugentar printfs. Ou debuga () - do Qt.
Swift - Friday Pie
1
Mesmo? É praticamente o primeiro exemplo do primeiro capítulo de tantos livros sobre C ++, se é que ele (com o uso do operador de inserção) é o único C ++ que alguns novos membros conhecem.
Mckenzm 29/07/19
@mckenzm Eu poderia colocá-lo em um livro ou em notas de aula para reduzir a desordem, mas não no código
Martin Beckett
45

Programadores experientes usam o que resolve seus problemas e evita o que cria novos problemas, além de evitar diretivas de uso no nível do arquivo de cabeçalho por esse motivo exato.

Programadores experientes também tentam evitar a qualificação completa de nomes em seus arquivos de origem. Uma razão menor para isso é que não é elegante escrever mais código quando menos código é suficiente, a menos que haja boas razões . Um dos principais motivos disso é desativar a pesquisa dependente de argumento (ADL).

Quais são essas boas razões ? Às vezes, os programadores explicitamente desejam desativar o ADL, outras vezes desejam desambiguar.

Portanto, o seguinte é OK:

  1. Usando diretivas e declarações de uso no nível de função nas implementações de funções
  2. Usando-declarações no nível do arquivo de origem dentro dos arquivos de origem
  3. (Às vezes) usando diretivas no nível do arquivo de origem
Alexander Poluektov
fonte
43

Concordo que não deve ser usado globalmente, mas não é tão ruim usar localmente, como em um namespace. Aqui está um exemplo de "A linguagem de programação C ++" :

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

Neste exemplo, resolvemos possíveis conflitos de nome e ambiguidades decorrentes de sua composição.

Os nomes declarados explicitamente lá (incluindo nomes declarados por declarações de uso como His_lib::String) têm prioridade sobre nomes disponibilizados em outro escopo por uma diretiva de uso ( using namespace Her_lib).

Oleksiy
fonte
29

Eu também considero uma prática ruim. Por quê? Apenas um dia pensei que a função de um espaço para nome é dividir as coisas, por isso não devo estragar tudo ao jogar tudo em uma bolsa global.

No entanto, se eu geralmente uso 'cout' e 'cin', escrevo: using std::cout; using std::cin;no arquivo .cpp (nunca no arquivo de cabeçalho como ele se propaga #include). Eu acho que ninguém sã jamais nomeará um fluxo coutou cin. ;)

Yelonek
fonte
7
Essa é uma declaração de uso local , uma coisa muito diferente de uma diretiva de uso .
Sbi
25

É bom ver o código e saber o que ele faz. Se eu vejo std::cout, sei que é o coutfluxo da stdbiblioteca. Se eu vejo cout, não sei. Ele poderia ser o coutfluxo da stdbiblioteca. Ou pode haver int cout = 0;dez linhas mais altas na mesma função. Ou uma staticvariável chamadacout nesse arquivo. Poderia ser qualquer coisa.

Agora pegue uma base de código de um milhão de linhas, que não é particularmente grande, e você está procurando por um bug, o que significa que você sabe que há uma linha nesse milhão de linhas que não faz o que deveria fazer. cout << 1;poderia ler um static intnome cout, deslocá-lo para a esquerda um pouco e jogar fora o resultado. Procurando por um bug, eu teria que verificar isso. Você pode ver como eu realmente prefiro ver std::cout?

É uma dessas coisas que parece realmente uma boa idéia se você é professor e nunca teve que escrever e manter nenhum código para viver. Adoro ver código onde (1) eu sei o que ele faz; e (2) estou confiante de que a pessoa que o escreveu sabia o que faz.

gnasher729
fonte
4
Como você sabe "std :: cout << 1" não está lendo um int estático chamado cout no namespace std, deslocando-o por um e jogando fora o resultado? Além disso, como você sabe o que "<<" faz;) ??? ... parece que esta resposta não é um bom ponto de dados para evitar 'usar'.
Nyholku
4
Se alguém redefiniu std :: cout para ser um número inteiro, seu problema não é técnico, mas social - alguém o tem para você. (e você provavelmente deve também verificar todos os cabeçalhos para coisas como verdadeiro falso #define, etc)
Jeremy Friesner
2
Quando vejo cout, sei que é std :: cout, sempre. Se eu estiver errado, é problema da pessoa que escreveu este código, não me :)
Tien Do
22

É tudo sobre gerenciamento de complexidade. Usar o espaço para nome puxa coisas que você não deseja e, portanto, dificulta a depuração (eu digo possivelmente). Usar std :: em todo o lugar é mais difícil de ler (mais texto e tudo isso).

Cavalos para cursos - gerencie sua complexidade da melhor maneira possível e se sinta capaz.

Preet Sangha
fonte
18

Considerar

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // Uh oh
};

Observe que este é um exemplo simples. Se você tiver arquivos com 20 inclusões e outras importações, terá várias dependências para resolver o problema. O pior é que você pode obter erros não relacionados em outros módulos, dependendo das definições em conflito.

Não é horrível, mas você evitará dores de cabeça ao não usá-lo nos arquivos de cabeçalho ou no espaço de nomes global. Provavelmente está tudo bem em escopos muito limitados, mas nunca tive problemas ao digitar os cinco caracteres extras para esclarecer de onde vêm minhas funções.

Ron Warholic
fonte
18
  1. Você precisa ler o código escrito por pessoas com opiniões diferentes sobre estilo e práticas recomendadas.

  2. Se você estiver usando apenas cout, ninguém fica confuso. Mas quando você tem muitos namespaces voando por aí e vê essa classe e não sabe exatamente o que faz, ter o namespace explícito atua como um tipo de comentário. Você pode ver à primeira vista, "oh, isso é uma operação de sistema de arquivos" ou "que está fazendo coisas de rede".

Dustin Getz
fonte
17

Usar muitos namespaces ao mesmo tempo é obviamente uma receita para o desastre, mas usar apenas o namespace stde o namespacestd não é tão importante na minha opinião porque a redefinição só pode ocorrer pelo seu próprio código ...

Portanto, considere-as como nomes reservados, como "int" ou "class", e é isso.

As pessoas devem parar de ser tão analistas sobre isso. Seu professor estava certo o tempo todo. Basta usar um espaço para nome; esse é o objetivo de usar espaços para nome em primeiro lugar. Você não deve usar mais de um ao mesmo tempo. A menos que seja seu. Então, novamente, a redefinição não acontecerá.

user2645752
fonte
Criando colisões não é tão difícil - cordas curta gosto min, ende lessaparecem no std::namespace. Mais ainda, agora que std::possui milhares de símbolos, é útil que o leitor saiba de onde vem um novo símbolo que talvez eles não saibam.
Tom Swirly
O namespace std existe porque as pessoas, você, seus colegas ou as pessoas que escrevem o middleware que você usa, nem sempre são sábias em colocar funções dentro dos namespaces. Portanto, você pode importar todo o std :: e nada mais, enquanto ainda invoca uma colisão entre, digamos, std :: min e o legado de outra pessoa :: min () antes da hora em que estava no std.
Aiken Drum
14

Concordo com os outros aqui, mas gostaria de abordar as preocupações relacionadas à legibilidade - você pode evitar tudo isso usando simplesmente typedefs na parte superior do seu arquivo, função ou declaração de classe.

Normalmente, eu o uso na minha declaração de classe, pois os métodos em uma classe tendem a lidar com tipos de dados semelhantes (os membros) e um typedef é uma oportunidade para atribuir um nome que seja significativo no contexto da classe. Isso realmente ajuda a legibilidade nas definições dos métodos de classe.

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

e na implementação:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

em oposição a:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

ou:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}
Carl
fonte
Apenas um pequeno comentário, enquanto typedef é útil, eu consideraria criar uma classe que represente Linhas em vez de usar typedef.
Eyal Solnik
14

Um exemplo concreto para esclarecer a preocupação. Imagine que você tem uma situação em que possui duas bibliotecas fooe bar, cada uma com seu próprio espaço para nome:

namespace foo {
    void a(float) { /* Does something */ }
}

namespace bar {
    ...
}

Agora, digamos que você use fooe barjuntos em seu próprio programa, da seguinte maneira:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

Neste ponto, está tudo bem. Quando você executa seu programa, ele 'faz alguma coisa'. Mas depois você atualiza bare digamos que mudou para:

namespace bar {
    void a(float) { /* Does something completely different */ }
}

Neste ponto, você receberá um erro do compilador:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

Portanto, você precisará fazer alguma manutenção para esclarecer que 'a' significava foo::a. Isso é indesejável, mas felizmente é bem fácil (basta adicionar foo::antes de todas as chamadas paraa que o compilador marcar como ambíguo).

Mas imagine um cenário alternativo em que a barra mudou para ficar assim:

namespace bar {
    void a(int) { /* Does something completely different */ }
}

Nesse ponto, sua ligação de a(42)repente se liga ao bar::ainvés defoo::a e em vez de fazer 'algo', ele faz 'algo completamente diferente'. Nenhum aviso do compilador ou qualquer coisa. Seu programa silenciosamente começa a fazer algo completo diferente do que antes.

Quando você usa um espaço para nome, está arriscando um cenário como esse, e é por isso que as pessoas se sentem desconfortáveis ​​usando espaços para nome. Quanto mais coisas em um espaço para nome, maior o risco de conflito, para que as pessoas fiquem ainda mais desconfortáveis ​​usando o espaço para nomestd para (devido ao número de coisas nesse espaço para nome) do que outros espaços para nome.

Em última análise, este é um compromisso entre gravabilidade vs. confiabilidade / manutenção. A legibilidade também pode levar em consideração, mas eu pude ver argumentos para isso de qualquer maneira. Normalmente, eu diria que a confiabilidade e a manutenção são mais importantes, mas, neste caso, você pagará constantemente o custo da gravabilidade por um impacto relativamente raro na confiabilidade / manutenção. A melhor opção será determinada em seu projeto e em suas prioridades.

Kevin
fonte
O segundo cenário encerra o acordo para mim. Não há namespaces novamente. Não é possível que alterações sutis na funcionalidade não sejam detectadas sob o capô.
precisa saber é o seguinte
13

Um espaço para nome é um escopo nomeado. Os espaços para nome são usados ​​para agrupar declarações relacionadas e manter itens separados. Por exemplo, duas bibliotecas desenvolvidas separadamente podem usar o mesmo nome para se referir a itens diferentes, mas um usuário ainda pode usar os dois:

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    // ...
}

namespace Yourlib{
    class Stack{ /* ... */ };
    // ...
}

void f(int max) {
    Mylib::Stack<int> s1(max); // Use my stack
    Yourlib::Stack    s2(max); // Use your stack
    // ...
}

Repetir um nome de espaço para nome pode ser uma distração para leitores e escritores. Conseqüentemente, é possível afirmar que nomes de um espaço para nome específico estão disponíveis sem qualificação explícita. Por exemplo:

void f(int max) {
    using namespace Mylib; // Make names from Mylib accessible
    Stack<int> s1(max); // Use my stack
    Yourlib::Stack s2(max); // Use your stack
    // ...
}

Os espaços para nome fornecem uma ferramenta poderosa para o gerenciamento de diferentes bibliotecas e de diferentes versões de código. Em particular, eles oferecem ao programador alternativas de como é explícito fazer referência a um nome não local.

Fonte: Uma visão geral da linguagem de programação C ++ por Bjarne Stroustrup

Rohan Singh
fonte
4
Muito interessante que uma resposta baseada em orientação de nenhuma outra que Bjarne Stroustrup ganhou -2 ... garoto Bjarne deve ter sido um programador pobre e inexperiente quando introduziu esse recurso no C ++
nyholku
@nyholku: Veja isso .
Sbi 4/15
10

Um exemplo em que using namespace stdgera um erro de compilação devido à ambiguidade da contagem, que também é uma função na biblioteca de algoritmos.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}
Nithin
fonte
2
::count--problema resolvido. Normalmente, você terá mais coisas do namespace std do que de outros lugares; portanto, manter a diretiva using namespace pode economizar a digitação.
PSKocik
O verdadeiro problema aqui é que o C ++ ainda possui nomes globais sem espaço para nome. Isso e o fato de que 'this' está implícito nos métodos causam tantos erros e problemas que nem consigo contá-los, mesmo com a variável 'count' correta. ;)
Aiken Drum
9

Isso não piora o desempenho do seu software ou projeto. A inclusão do espaço para nome no início do seu código-fonte não é ruim. A inclusão das using namespace stdinstruções varia de acordo com suas necessidades e a maneira como você está desenvolvendo o software ou projeto.

O namespace stdcontém as funções e variáveis ​​padrão do C ++. Esse espaço para nome é útil quando você costuma usar as funções padrão do C ++.

Como é mencionado nesta página :

A declaração usando o namespace std é geralmente considerada uma prática ruim. A alternativa a essa instrução é especificar o espaço para nome ao qual o identificador pertence usando o operador scope (: :) cada vez que declaramos um tipo.

E veja esta opinião :

Não há problema em usar "using namespace std" em seu arquivo de origem quando você faz muito uso do namespace e sabe com certeza que nada irá colidir.

Algumas pessoas disseram que é uma prática ruim incluir os using namespace stdarquivos de origem porque você está chamando desse espaço de nome todas as funções e variáveis. Quando você deseja definir uma nova função com o mesmo nome que outra função contida no, namespace stdvocê sobrecarrega a função e isso pode gerar problemas devido à compilação ou execução. Não será compilado ou executado conforme o esperado.

Conforme mencionado nesta página :

Embora a instrução nos evite digitar std :: sempre que desejamos acessar uma classe ou tipo definido no espaço para nome std, ela importa a totalidade do espaço para nome std no espaço para nome atual do programa. Vamos dar alguns exemplos para entender por que isso pode não ser uma coisa tão boa

...

Agora, em um estágio posterior de desenvolvimento, desejamos usar outra versão do cout, que é implementada de maneira personalizada em alguma biblioteca chamada “foo” (por exemplo)

...

Observe como existe uma ambiguidade, para qual biblioteca o cout aponta? O compilador pode detectar isso e não compilar o programa. Na pior das hipóteses, o programa ainda pode ser compilado, mas chamar a função incorreta, pois nunca especificamos a qual namespace o identificador pertencia.

CryogenicNeo
fonte
7

Não acho que seja necessariamente uma má prática sob todas as condições, mas você precisa ter cuidado ao usá-la. Se você estiver escrevendo uma biblioteca, provavelmente deverá usar os operadores de resolução de escopo com o espaço para nome para impedir que sua biblioteca se incomode com outras bibliotecas. Para o código no nível do aplicativo, não vejo nada de errado com ele.

Dr. Watson
fonte
7

"Por que 'using namespace std;' considerada uma má prática em C ++? "

Digo o contrário: por que digitar cinco caracteres extras é considerado complicado por alguns?

Considere, por exemplo, escrever um software numérico. Por que eu consideraria poluir meu espaço de nome global cortando "std :: vector" geral em "vetor" quando "vetor" é um dos conceitos mais importantes do domínio do problema?

Solkar
fonte
19
Não são apenas 5 caracteres extras; seus 5 caracteres extras toda vez que você faz referência a qualquer tipo de objeto na biblioteca padrão. O que, se você estiver usando muito a biblioteca padrão, será frequentemente. Portanto, são mais realisticamente milhares de caracteres extras em um programa de tamanho decente. Presumivelmente, a 'usando' directiva foi adicionado à linguagem de modo que pudesse ser usado ...
Jeremy Friesner
5
Não são 5 caracteres extras a cada vez, são 5 caracteres e, provavelmente, alguns cliques do mouse para abrir um menu e fazer uma busca e substituição no editor de sua escolha.
DaveWalley
1
Legibilidade. cout << hex << setw(4) << i << endl;é mais fácil de ler do questd::cout << std::hex << std::setw(4) << i << std::endl;
oz1cz
16
E ainda pior: std::map<std::string,std::pair<std::string,std::string>>é horrível em comparação com map<string,pair<string,string>>.
oz1cz
4
É uma boa prática digitar os contêineres STL de qualquer maneira, para que std :: realmente não importe. E o C ++ 11 nos trouxe a palavra-chave auto, que torna as coisas ainda mais fáceis quando, por exemplo, o uso de iteradores.
juzzlin
7

Eu concordo com os outros - está pedindo conflitos de nome, ambiguidades e, em seguida, o fato é que é menos explícito. Embora eu possa ver o uso de using, minha preferência pessoal é limitá-lo. Eu também consideraria fortemente o que alguns outros apontaram:

Se você deseja encontrar um nome de função que possa ser um nome bastante comum, mas somente no stdespaço para nome (ou o inverso - você deseja alterar todas as chamadas que não estão no espaço para nome std, espaço para nome X, ...), então como você se propõe a fazer isso?

Você poderia escrever um programa para fazê-lo, mas não seria melhor gastar tempo trabalhando no seu projeto em vez de escrever um programa para mantê-lo?

Pessoalmente, na verdade não me importo com o std::prefixo. Eu gosto do visual mais do que não tê-lo. Não sei se é porque é explícito e me diz "esse não é o meu código ... estou usando a biblioteca padrão" ou se é outra coisa, mas acho que parece melhor. Isso pode ser estranho, já que eu entrei recentemente em C ++ (usei e ainda faço C e outras linguagens por muito mais tempo e C é minha linguagem favorita de todos os tempos, logo acima do assembly).

Há uma outra coisa, embora esteja um pouco relacionada ao que foi dito acima e ao que outros apontam. Embora isso possa ser uma prática ruim, às vezes eu reservo std::namea versão da biblioteca padrão e o nome da implementação específica do programa. Sim, de fato, isso pode te morder e te morder com força, mas tudo se resume ao fato de eu ter iniciado esse projeto do zero, e eu sou o único programador para ele. Exemplo: eu sobrecarrego std::stringe chamo string. Eu tenho adições úteis. Eu fiz isso em parte por causa da minha tendência C e Unix (+ Linux) para nomes em letras minúsculas.

Além disso, você pode ter alias de namespace. Aqui está um exemplo de onde é útil que pode não ter sido referido. Eu uso o padrão C ++ 11 e especificamente com libstdc ++. Bem, ele não tem std::regexsuporte completo . Certamente, ele compila, mas gera uma exceção ao longo das linhas de ser um erro no final do programador. Mas é falta de implementação.

Então, aqui está como eu resolvi isso. Instale a regex do Boost e vincule-a. Em seguida, faça o seguinte para que, quando o libstdc ++ for totalmente implementado, eu precise apenas remover esse bloco e o código permanecer o mesmo:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

Não vou discutir se isso é uma má ideia ou não. No entanto, argumentarei que ele o mantém limpo para o meu projeto e, ao mesmo tempo, o torna específico: É verdade que preciso usar o Boost, mas estou usando-o como o libstdc ++ eventualmente o terá. Sim, iniciar seu próprio projeto e começar com um padrão (...) desde o início ajuda muito na manutenção, desenvolvimento e tudo o que está envolvido no projeto!

Apenas para esclarecer uma coisa: na verdade, não acho que seja uma boa ideia usar o nome de uma classe / o que quer que seja no STL deliberadamente e mais especificamente no lugar de. A string é a exceção (ignore o primeiro, acima ou o segundo aqui, trocadilhos, se necessário) para mim, pois eu não gostei da ideia de 'String'.

Como é, ainda sou muito tendencioso em relação a C e tendencioso em relação a C ++. Detalhes poupadores, muito do que eu trabalho se encaixa mais em C (mas foi um bom exercício e uma boa maneira de me obrigar a. Aprender outro idioma eb. Tentar não ser menos tendencioso contra objetos / classes / etc, o que talvez seja melhor declarado menos mente fechada, menos arrogante e mais receptiva.). Mas o que é útil é o que alguns já sugeriram: eu realmente uso list (é bastante genérico, não é?) E ordeno (a mesma coisa) para nomear dois que causariam um conflito de nomes se eu o fizesse using namespace std;, e assim para esse fim, prefiro ser específico, controlar e saber que, se pretender que seja o uso padrão, terei que especificá-lo. Simplificando: não é permitido assumir.

E quanto a fazer parte da regex do Boost std. Faço isso para integração futura e - novamente, admito que isso é parcialidade - não acho que seja tão feio quanto boost::regex:: .... De fato, isso é outra coisa para mim. Ainda há muitas coisas em C ++ que ainda tenho que aceitar totalmente em aparência e métodos (outro exemplo: modelos variados versus argumentos var [embora eu admita que modelos variados sejam muito úteis!]). Mesmo aqueles que eu aceito foram difíceis, e ainda tenho problemas com eles.

Peter Mortensen
fonte
1
Estender o stdespaço para nome é um comportamento indefinido e, portanto, nunca deve ser feito.
22418 Tambour
7

De minhas experiências, se você tem várias bibliotecas que usam o say cout, mas para um propósito diferente, pode usar o errado cout.

Por exemplo, se eu digitar, using namespace std;ee using namespace otherlib;digitar apenas cout(o que acontece em ambos), em vez de std::cout(ou 'otherlib::cout'), você poderá usar o incorreto e obter erros. É muito mais eficaz e eficiente de usar std::cout.

Engine Dev
fonte
6

Com identificadores importados não qualificados, você precisa de ferramentas de pesquisa externas, como grep, para descobrir onde os identificadores são declarados. Isso dificulta o raciocínio sobre a correção do programa.

August Karlstrom
fonte
6

Depende de onde está localizado. Se for um cabeçalho comum, você estará diminuindo o valor do espaço para nome, mesclando-o no espaço para nome global. Lembre-se de que essa pode ser uma maneira interessante de tornar os módulos globais.

MathGladiator
fonte
6

Essa é uma prática ruim, geralmente conhecida como poluição de namespace global. Podem ocorrer problemas quando mais de um espaço para nome tem o mesmo nome da função com a assinatura; será ambíguo para o compilador decidir qual chamar e tudo isso pode ser evitado quando você especificar o espaço para nome com a sua chamada de função std::cout. Espero que isto ajude. :)

adn.911
fonte
5

Para responder à sua pergunta, eu a encaro da seguinte forma: muitos programadores (nem todos) invocam o namespace std. Portanto, deve-se ter o hábito de NÃO usar coisas que colidem ou usam os mesmos nomes do que está no espaço de nomes std. Isso é bastante concedido, mas não tanto em comparação com o número possível de palavras coerentes e pseudônimos que podem ser apresentados estritamente.

Quero dizer realmente ... dizer "não confie nisso estando presente" é apenas configurá-lo para confiar que NÃO está presente. Você sempre terá problemas para emprestar trechos de código e repará-los constantemente. Apenas mantenha seu material definido pelo usuário e emprestado em um escopo limitado, como deve ser, e seja MUITO poupador de globais (honestamente, os globais devem quase sempre ser o último recurso para fins de "compilar agora, sanidade posterior"). Na verdade, acho que é um mau conselho do seu professor, porque usar std funcionará tanto para "cout" quanto "std :: cout", mas NÃO usar std funcionará apenas para "std :: cout". Você nem sempre terá a sorte de escrever todo o seu próprio código.

NOTA: Não se concentre muito em questões de eficiência até aprender um pouco sobre como os compiladores funcionam. Com um pouco de experiência em codificação, você não precisa aprender muito sobre eles antes de perceber o quanto eles são capazes de generalizar um bom código em algo simples. Tão simples quanto se você tivesse escrito tudo em C. Um bom código é tão complexo quanto precisa.

Noneyo Getit
fonte
Dado quantas pessoas desconhecem as funções úteis da biblioteca padrão (reinventar coisas de <algorithm>, por exemplo), parece um pouco exagerado imaginar que as mesmas pessoas poderiam evitar com segurança esses identificadores. Examine seu próprio código e me diga que você nunca tem uma variável ou função chamada count. Ou distance, ou log, destroy, launch, visit, beta, sample, messages, clamp, erase, copy, modulus, left, etc. Para não mencionar todos os identificadores ainda não no stdque vai quebrar seu código quando C ++ 35 sai ...
Toby Speight