type - why we use using namespace std in c++




Por que “usar namespace std” é considerado uma prática ruim? (20)

Não use globalmente

Considera-se "ruim" somente quando usado globalmente . Porque:

  • Você atravessa o namespace no qual está programando.
  • Os leitores terão dificuldade em ver de onde vem um identificador em particular, quando você usa muitos using namespace xyz .
  • O que quer que seja verdade para outros leitores do seu código-fonte é ainda mais verdadeiro para o leitor mais frequente: você mesmo. Volte daqui a um ano ou dois e dê uma olhada ...
  • Se você só fala sobre o using namespace std você pode não estar ciente de todas as coisas que você pega - e quando você adiciona outro #include ou move para uma nova revisão do C ++, você pode receber conflitos de nome dos quais não estava ciente.

Você pode usá-lo localmente

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

Um idioma para usá-lo localmente

Em C ++ 03, havia um idioma - código clichê - para implementar uma função de swap para suas classes. Foi sugerido que você realmente use 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::swap para value_ , isto é, void std::swap(int, int) .
  • Se você tiver um void swap(Child&, Child&) sobrecarga void swap(Child&, Child&) implementado, o compilador irá escolhê-lo.
  • Se você não tiver essa sobrecarga, o compilador usará o void std::swap(Child&,Child&) e tentará alterná-los da melhor forma possível.

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

Eu tenho dito por outros que escrever using namespace std no código está errado, e que eu deveria usar std::cout e std::cin diretamente em vez disso.

Por que using namespace std considerado uma prática ruim? É ineficiente ou arrisca declarar variáveis ​​ambíguas (variáveis ​​que compartilham o mesmo nome de uma função no namespace std )? Isso afeta o desempenho?


  1. você precisa ser capaz de ler código escrito por pessoas que têm diferentes estilos e melhores práticas de opinião do que você.

  2. Se você está apenas usando cout, ninguém fica confuso. Mas quando você tem muitos namespaces voando e vê essa classe e não sabe exatamente o que ela faz, ter o espaço de nomes explícito age como um comentário. Você pode ver à primeira vista, 'oh, isso é uma operação do sistema de arquivos' ou 'isso é fazer coisas de rede'.


É tudo sobre gerenciamento de complexidade. Usar o namespace vai puxar coisas que você não quer e, assim, possivelmente dificultar 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 sente capaz.


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

O Library Foo 2.0 poderia introduzir uma função, Quux() , que é uma combinação inequivocamente melhor para algumas de suas chamadas para o Quux() que para o bar::Quux() seu código chamou por anos. Então seu código ainda compila , mas chama silenciosamente a função errada e sabe Deus o quê. Isso é tão ruim quanto as coisas podem ficar.

Tenha em mente que o namespace std tem toneladas de identificadores, muitos dos quais são muito comuns ( list pensamento, sort , string , iterator , etc.) que provavelmente aparecerão em outro código também.

Se você considerar isso improvável: Houve uma pergunta aqui no em que praticamente exatamente isso aconteceu (função errada chamada devido ao omitido std:: prefix) cerca de meio ano depois que eu dei essa resposta. Here está outro exemplo mais recente de tal questão. Então este é um problema real.

Aqui está mais um ponto de dados: Muitos, muitos anos atrás, eu também achei irritante ter que prefixar tudo da biblioteca padrão com std:: . Então, trabalhei em um projeto no qual foi decidido, no começo, que tanto as diretivas quanto as declarações eram proibidas, exceto para escopos de função. Adivinha? Levou a maioria de nós muito poucas semanas para se acostumar a escrever o prefixo, e depois de mais algumas semanas a maioria de nós chegou a concordar que isso realmente tornava o código mais legível . Há uma razão para isso: se você gosta de prosa mais curta ou mais longa é subjetivo, mas os prefixos adicionam objetivamente clareza ao código. Não apenas o compilador, mas você também acha mais fácil ver qual identificador é referido.

Em uma década, esse projeto cresceu para ter vários milhões de linhas de código. Uma vez que essas discussões surgiram de novo e de novo, certa vez fiquei curioso com a frequência com que o using escopo da função (permitido) era realmente usado no projeto. Eu grep'd as fontes para isso e só encontrei uma ou duas dúzias de lugares onde foi usado. Para mim, isso indica que, uma vez tentados, os desenvolvedores não acham difícil o bastante empregar diretivas usando uma vez a cada 100 kLoC, mesmo quando permitido usá-las.

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


Eu também considero uma prática ruim. Por quê? Apenas um dia eu pensei que a função de um namespace é dividir as coisas, então eu não deveria estragar tudo colocando tudo em uma só bolsa global. No entanto, se eu costumo usar 'cout' e 'cin', escrevo: using std::cout; using std::cin; using std::cout; using std::cin; no arquivo cpp (nunca no arquivo de cabeçalho conforme ele se propaga com #include ). Eu acho que ninguém sã jamais vai nomear um fluxo ou cin . ;)


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

using namespace foo;
using namespace bar;

Tudo funciona bem, você pode chamar Blah() de Foo e Quux() de 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: Tanto o Foo 2.0 quanto o Bar importam o Quux() para o seu namespace global. Isso vai levar algum esforço para corrigir, especialmente se os parâmetros da função coincidirem.

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


O problema de colocar using namespace nos arquivos de cabeçalho de suas classes é que isso força qualquer um que queira usar suas classes (incluindo seus arquivos de cabeçalho) a também 'usando' (isto é, vendo tudo) aqueles outros namespaces.

No entanto, você pode se sentir livre para colocar uma instrução using em seus arquivos (privados) * .cpp.

Cuidado que algumas pessoas discordam do meu dizer "sinta-se livre" assim - porque, embora uma instrução using em um arquivo cpp seja melhor que em um cabeçalho (porque não afeta pessoas que incluem seu arquivo de cabeçalho), eles acham que ainda é não é bom (porque dependendo do código pode tornar a implementação da classe mais difícil de manter). Este tópico da FAQ diz:

A diretiva using existe para código C ++ legado e para facilitar a transição para namespaces, mas você provavelmente não deve usá-lo regularmente, pelo menos não em 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:";
    

Outra razão é surpresa.

Se eu vejo cout << blah , em vez de std::cout << blah

Eu acho o que é isso? É a cout normal? Isso é algo especial?


Recentemente encontrei uma reclamação sobre o Visual Studio 2010 . Descobriu-se que praticamente todos os arquivos de origem tinham essas duas linhas:

using namespace std;
using namespace boost;

Um monte de recursos Boost estão indo para o padrão C ++ 0x, e Visual Studio 2010 tem um monte de recursos C ++ 0x, então, de repente, esses programas não estavam compilando.

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


Se você importar os arquivos de cabeçalho corretos, de repente você terá nomes como hex , left , plus ou count em seu escopo global. Isso pode ser surpreendente se você não estiver ciente de que std:: contém esses nomes. Se você também tentar usar esses nomes localmente, isso pode causar muita confusão.

Se todas as coisas padrão estiverem em seu próprio namespace, você não precisa se preocupar com colisões de nomes com seu código ou outras bibliotecas.


Versão curta: não use globais usando declarações ou diretivas em arquivos de cabeçalho. Sinta-se à vontade para usá-los em arquivos de implementação. Aqui está o que Herb Sutter e Andrei Alexandrescu têm a dizer sobre este assunto em Padrões de Codificação C ++ (negrito para ênfase é meu):

Resumo

Os namespace usings são para sua conveniência, não para você infligir a terceiros: nunca escreva uma declaração using ou using directive antes de uma diretiva #include.

Corolário: Nos arquivos de cabeçalho, não escreva no nível do namespace usando diretivas ou usando 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 o que outros #includes de cabeçalho podem aparecer depois deles.)

Discussão

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 .


Considerar

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


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

class stringstream {  // uh oh
};

Note que este é um exemplo simples, se você tiver arquivos com 20 includes e outras importações, você terá uma tonelada de dependências para resolver o problema. A pior coisa é que você pode obter erros não relacionados em outros módulos, dependendo das definições que entram em conflito.

Não é horrível, mas você vai se poupar dores de cabeça por não usá-lo em arquivos de cabeçalho ou no namespace global. É provavelmente certo fazê-lo em escopos muito limitados, mas eu nunca tive problema em digitar os 5 caracteres extras para esclarecer de onde minhas funções estão vindo.


Um exemplo em que usar namespace std gera erro de complilação devido à ambigüidade 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;
}

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

Eu coloquei ao contrário: Por que a digitação de 5 caracteres extras é considerada incômoda por alguns?

Considere, por exemplo, escrever um software numérico, por que eu consideraria poluir meu namespace global cortando "std :: vector" geral para "vector" quando "vector" é um dos conceitos mais importantes do domínio do problema?


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

Por exemplo, se eu digitar, using namespace std;e using namespace otherlib;digitar apenas cout (que por acaso está em ambos), em vez de std::cout(ou 'otherlib::cout'), você pode usar o errado e obter erros, é muito mais eficiente e eficiente de usar std::cout.


Depende de onde está localizado. Se for um cabeçalho comum, você estará diminuindo o valor do namespace mesclando-o no namespace global. Lembre-se de que essa pode ser uma boa maneira de criar globals de módulo.


Eu concordo com os outros - está pedindo confrontos de nome, ambigüidades 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 outros apontaram:

Se você quiser encontrar um nome de função que pode ser um nome bastante comum, mas você só quer encontrá-lo no stdnamespace (ou o inverso - você quer mudar todas as chamadas que não estão no namespace std, namespace X, ...), então, como você propõe fazer isso? Você poderia escrever um programa para fazer isso, mas não seria melhor gastar tempo trabalhando em seu projeto em vez de escrever um programa para manter seu projeto?

Pessoalmente eu realmente não me importo com o std::prefixo. Eu gosto do olhar mais do que não tê-lo. Eu não sei se isso é porque é explícito e diz para mim "este não é o meu código ... eu estou usando a biblioteca padrão" ou se é outra coisa, mas eu acho que parece mais legal. Isso pode ser estranho, dado que eu só recentemente entrei 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 da montagem).

Há uma outra coisa, embora seja algo relacionado ao que foi dito acima e ao que outros apontam. Embora isso possa ser uma prática ruim, eu às vezes reservo std::namepara a versão da biblioteca padrão e nomeio para a implementação específica do programa. Sim, sim, isso poderia te morder e te morder, mas tudo se resume a que eu comecei este projeto a partir do zero e eu sou o único programador para isso. 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) em relação a nomes de minúsculas.

Além disso, você pode ter aliases 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, não tem std::regexsuporte completo . Claro que compila, mas lança 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 o regex do Boost, vincule-o. Então, eu faço o seguinte para que, quando o libstdc ++ tiver implementado completamente, eu precise remover apenas esse bloco e o código permaneça 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, vou argumentar que 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 o seu próprio projeto e começar com um padrão (...) no início, ajuda muito na manutenção, desenvolvimento e tudo o que está envolvido no projeto!

Editar:
Agora que tenho tempo, só para esclarecer alguma coisa. Eu realmente não acho que é uma boa idéia usar um nome de uma classe / qualquer coisa no STL deliberadamente e mais especificamente no lugar de. A string é a exceção (ignorar o primeiro, acima ou segundo aqui, trocadilho se você deve) para mim, como eu não gostei da idéia de 'String'. Como é, ainda sou muito tendencioso em relação ao C e tendencioso contra o C ++. Poucos detalhes, muito do que eu trabalho em C se encaixa mais (mas foi um bom exercício e uma boa maneira de fazer-me um. Aprender outra língua e b. Tente não ser menos tendencioso contra objeto / classes / etc que talvez seja melhor indicado como menos mente fechada, menos arrogante, mais tolerante.) Mas o que é útil é o que alguns já sugeriram: eu realmente uso list (é bastante genérico, não é?),sort (same thing) para nomear dois que causariam um confronto de nome se eu fizesseusing namespace std;e assim, para esse fim, prefiro ser específico, controlar e saber que, se pretendo que seja o uso padrão, terei que especificá-lo. Simplificando: não assumindo permitido.

E quanto a fazer parte do regex de Boost std. Eu faço isso para integração futura e - mais uma vez, admito que isso é completamente preconceituoso - eu não acho que isso é tão feio quanto boost::regex:: ...De fato isso é outra coisa para mim. Há muitas coisas em C ++ que eu ainda tenho que aceitar totalmente em aparências e métodos (outro exemplo: templates variadic versus var args [embora eu admita que os modelos variadic são muito muito úteis!)]. Mesmo aqueles que eu aceito, foi difícil E ainda tenho problemas com eles.


Eu 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ê está escrevendo uma biblioteca, você provavelmente deve usar os operadores de resolução de escopo com o namespace para manter sua biblioteca de cabeçadas com outras bibliotecas. Para o código de nível de aplicativo, não vejo nada de errado com isso.


Para responder à sua pergunta, eu vejo isso da seguinte maneira: muitos programadores (não todos) invocam o namespace std. Portanto, deve-se ter o hábito de NÃO usar coisas que colidam ou usam os mesmos nomes do que está no namespace std. Isso é um grande negócio concedido, mas não muito em comparação com o número de possíveis palavras coerentes e pseudônimos que podem surgir estritamente falando.

Quero dizer, realmente ... dizer "não confie em isso estar presente" é apenas configurá-lo para contar com ele não estar presente. Você está constantemente tendo problemas para emprestar trechos de códigos e consertá-los constantemente. Apenas mantenha seu material definido pelo usuário e emprestado em um escopo limitado como deveria ser e seja MUITO BEM com globals (honestamente globals devem ser quase sempre um último recurso para fins de "compilar agora, sanidade mais tarde"). Realmente eu acho que é um mau conselho do seu professor porque usar std funcionará tanto para "cout" quanto para "std :: cout", mas NÃO usar std funcionará apenas para "std :: cout". Você não será sempre afortunado o suficiente para escrever todo o seu próprio código.

NOTA: Não se concentre muito em questões de eficiência até que você realmente aprenda um pouco sobre como os compiladores funcionam. Com um pouco de experiência de 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 como se você tivesse escrito tudo em C. Um bom código é tão complexo quanto precisa ser.


Um exemplo concreto para esclarecer a preocupação. Imagine que você tem uma situação onde você tem 2 bibliotecas, foo e bar, cada uma com seu próprio namespace:

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

namespace bar {
    ...
}

Agora, digamos que você use foo e bar juntos em seu próprio programa da seguinte maneira:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

Neste ponto tudo está bem. Quando você executa seu programa, "faz alguma coisa". Mas depois você atualiza bar e digamos que mudou para ser assim:

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)
}

Então você precisa fazer alguma manutenção para esclarecer qual 'a' você quis dizer (ou seja foo::a). Isso é provavelmente indesejável, mas felizmente é muito fácil (basta adicionar foo::na frente de todas as chamadas para ao compilador que as marcas sejam ambíguas).

Mas imagine um cenário alternativo em que o bar mudou para ficar assim:

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

Neste ponto, seu chamado para ligar- a(42)se de repente ao bar::ainvés de foo::ae ao invés de fazer algo, faz algo completamente diferente. Nenhum aviso de compilador ou qualquer coisa. Seu programa apenas silenciosamente começa a fazer algo completamente diferente do que antes.

Quando você usa um namespace, está arriscando um cenário como esse, e é por isso que as pessoas se sentem desconfortáveis ​​usando namespaces. Quanto mais coisas em um namespace, maior o risco de conflito, portanto, as pessoas podem ficar ainda mais desconfortáveis ​​usando namespace std (devido ao número de coisas nesse namespace) do que em outros namespaces.

Em última análise, este é um trade-off entre capacidade de escrita versus confiabilidade / manutenção. A legibilidade também pode ser incluída, mas pude ver argumentos para isso de qualquer forma. Normalmente, eu diria que a confiabilidade e a facilidade de manutenção são mais importantes, mas nesse caso você pagará constantemente o custo de gravabilidade por um impacto bastante raro de confiabilidade / manutenção. O melhor compromisso determinará seu projeto e suas prioridades.







c++-faq