GeeksforGeeks
On Janeiro 16, 2022 by adminA declaração usando namespace std é geralmente considerada má prática. A alternativa a esta declaração é especificar o namespace ao qual o identificador pertence usando o operador de escopo(::) cada vez que declaramos um tipo.
Embora a instrução nos salve de digitar std:: sempre que desejarmos acessar uma classe ou tipo definido no namespace std, ela importa a totalidade do namespace std para o namespace atual do programa. Vamos pegar alguns exemplos para entender porque isso pode não ser uma coisa tão boa
Deixe-nos dizer que desejamos usar o espaço de nomes std. Então nós escrevemos
Exemplo 1:
#include <iostream>
using
namespace
std;
cout <<
" Something to Display"
;
Agora numa fase posterior de desenvolvimento, queremos usar outra versão do cout que é customizada implementada em alguma biblioteca chamada “foo” (por exemplo)
#include <foo.h>
#include <iostream>
using
namespace
std;
cout <<
" Something to display"
;
Notem como há uma ambiguidade, a que biblioteca se refere? O compilador pode detectar isso e não compilar o programa. No pior caso, o programa ainda pode compilar mas chamar a função errada, já que nunca especificamos a que espaço de nomes o identificador pertenceu.
Namespaces foram introduzidos em C++ para resolver conflitos de nomes de identificadores. Isto garantiu que dois objetos podem ter o mesmo nome e ainda ser tratados diferentemente se pertencessem a espaços de nomes diferentes. Observe como exatamente o oposto ocorreu neste exemplo. Ao invés de resolver um conflito de nomes, nós na verdade criamos um conflito de nomes.
Quando importamos um namespace, estamos essencialmente puxando todas as definições de tipo para o escopo atual. O espaço de nomes std é enorme. Ele tem centenas de identificadores predefinidos, então é possível que um desenvolvedor possa ignorar o fato de que existe outra definição de seu objeto pretendido na biblioteca std. Sem saber disso, eles podem proceder para especificar sua própria implementação e esperar que ela seja usada em partes posteriores do programa. Assim, haveria duas definições para o mesmo tipo no namespace atual. Isto não é permitido em C++, e mesmo que o programa compila não há como saber qual definição está sendo usada onde.
A solução para o problema é especificar explicitamente a qual espaço de nomes nosso identificador pertence usando o operador do escopo (:::). Assim, uma solução possível para o exemplo acima pode ser
#include <foo>
#include <iostream>
std::cout <<
"Something to display"
;
foo::cout <
"Something to display"
;
Mas tendo que digitar std:: cada vez que definimos um tipo é enfadonho. Isso também faz nosso código parecer mais tedioso com muitas definições de tipo e torna difícil a leitura do código. Considere por exemplo o código para obter a hora atual no programa
Exemplo 2:
#include <chrono>
#include <iostream>
auto
start = std::chrono::high_performance_clock::now()
auto
stop
= std::chrono::high_peformance_clock::now();
auto
duration
= std::duration_cast<std::chrono::milliseconds>(stop - start);
O código-fonte que está repleto de definições de tipo complicado e longo não é muito fácil de ler. Isto é algo que os desenvolvedores procuram evitar, uma vez que a manutenção do código é principalmente importante para eles.
Existem algumas maneiras de resolver este dilema, ou seja, especificar um espaço de nomes exato sem a necessidade de lixo de código com palavras-chave std.
Considerando usando typedefs
typedefs nos salva de escrever definições de tipos longos. No nosso exemplo 1, poderíamos resolver o problema usando dois typedefs um para a biblioteca std e outro para foo
#include <foo>
#include <iostream>
typedef
std::cout cout_std;
typedef
foo::cout cout_foo;
cout_std <<
"Something to write"
;
cout_foo <<
"Something to write"
;
Em vez de importar namespaces inteiros, importar um namespace truncado
No exemplo 2, poderíamos ter importado apenas o namespace chrono sob std.
#include <chrono>
#include <iostream>
using
std::chrono;
auto
start = high_performance_clock::now();
auto
stop = high_performance_clock::now();
auto
duration duration_cast<milliseconds>(stop - start);
Também podemos usar a declaração para importar um único identificador. Para importar apenas std::cout poderíamos usar
using std::cout;
Se você ainda importar namespaces inteiros, tente fazê-lo dentro de funções ou escopo limitado e não no escopo global.
Utilize a instrução “using namespace std” dentro das definições de funções ou classe, definições estruturais. Ao fazer isso, as definições do namespace são importadas para um escopo local, e pelo menos sabemos onde os possíveis erros podem se originar se eles surgirem.
#include <isotream>
using
namespace
std;
void
foo()
{
using
namespace
std;
}
Conclusão.
Discutimos métodos alternativos para acessar um identificador a partir de um namespace. Em todos os casos, evite importar espaços de nomes inteiros para o código fonte.
Embora boas práticas de codificação possam levar algum tempo para aprender e desenvolver, elas geralmente pagam a longo prazo. Escrever código limpo, inequívoco e robusto, sem erros, deve ser a intenção de qualquer programador.
Deixe uma resposta