GeeksforGeeks
On 16 ledna, 2022 by adminPříkaz using namespace std je obecně považován za špatný postup. Alternativou k tomuto příkazu je specifikovat jmenný prostor, do kterého identifikátor patří, pomocí operátoru scope(::) při každé deklaraci typu.
Příkaz nás sice ušetří psaní std:: pokaždé, když chceme přistupovat ke třídě nebo typu definovanému ve jmenném prostoru std, ale importuje celý jmenný prostor std do aktuálního jmenného prostoru programu. Uveďme si několik příkladů, abychom pochopili, proč to nemusí být tak dobrá věc
Řekněme, že chceme použít cout ze jmenného prostoru std. Napíšeme tedy
Příklad 1:
..
#include <iostream>
using
namespace
std;
cout <<
" Something to Display"
;
Nyní v pozdější fázi vývoje, chceme použít jinou verzi cout, která je implementována na zakázku v nějaké knihovně s názvem „foo“ (například)
.
#include <foo.h>
#include <iostream>
using
namespace
std;
cout <<
" Something to display"
;
Všimněte si, jak je zde dvojznačnost, na kterou knihovnu ukazuje cout? Překladač to může zjistit a program nezkompilovat. V horším případě se program přesto může zkompilovat, ale zavolá špatnou funkci, protože jsme nikdy nespecifikovali, do kterého jmenného prostoru identifikátor patří.
Jmenné prostory byly do jazyka C++ zavedeny kvůli řešení konfliktů jmen identifikátorů. Tím bylo zajištěno, že dva objekty mohou mít stejné jméno, a přesto s nimi může být zacházeno odlišně, pokud patří do různých jmenných prostorů. Všimněte si, že v tomto příkladu došlo k přesnému opaku. Místo řešení konfliktu jmen ve skutečnosti vytváříme konflikt jmen.
Když importujeme prostor jmen, v podstatě přitahujeme všechny definice typů do aktuálního oboru. Prostor jmen std je obrovský. Má stovky předdefinovaných identifikátorů, takže je možné, že vývojář přehlédne, že v knihovně std existuje jiná definice jím zamýšleného objektu. Bez vědomí této skutečnosti může přistoupit k zadání vlastní implementace a očekávat, že bude použita v pozdějších částech programu. V aktuálním jmenném prostoru by tak existovaly dvě definice téhož typu. To je v C++ nepřípustné, a i když se program zkompiluje, není možné zjistit, která definice je kde použita.
Řešením problému je explicitně určit, do kterého jmenného prostoru náš identifikátor patří, pomocí operátoru scope (::). Jedno z možných řešení výše uvedeného příkladu tedy může být
#include <foo>
#include <iostream>
std::cout <<
"Something to display"
;
foo::cout <
"Something to display"
;
Ale nutnost zadat std:: pokaždé, když definujeme nějaký typ, je únavné. Také to dělá náš kód chlupatější se spoustou definic typů a ztěžuje to čtení kódu. Vezměme si například kód pro získání aktuálního času v programu
Příklad 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);
Zdrojový kód, který se hemží složitými a dlouhými definicemi typů, není příliš přehledný. Tomu se vývojáři snaží vyhnout, protože je pro ně důležitá hlavně udržovatelnost kódu.
Existuje několik způsobů, jak toto dilema vyřešit, tj. přesně specifikovat jmenný prostor, aniž bychom kód zaplevelili klíčovými slovy std.
Zvažte použití typů
typové definice nás ušetří psaní dlouhých definic typů. V našem příkladu 1, jsme mohli problém vyřešit pomocí dvou typedefů, jednoho pro knihovnu std a druhého pro 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"
;
Místo importu celých jmenných prostorů, importovat zkrácený jmenný prostor
V příkladu 2 jsme mohli pod std importovat pouze jmenný prostor chrono.
#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);
Příkaz můžeme použít i pro import jednoho identifikátoru. Pro import pouze std::cout bychom mohli použít
using std::cout;
Pokud přesto importujete celé jmenné prostory, snažte se tak činit uvnitř funkcí nebo v omezeném rozsahu a ne v globálním rozsahu.
Příkaz „using namespace std“ používejte uvnitř definic funkcí nebo definic tříd, struktur. Tím se definice jmenných prostorů importují do lokálního oboru a my alespoň víme, kde mohou vzniknout případné chyby, pokud se vyskytnou.
#include <isotream>
using
namespace
std;
void
foo()
{
using
namespace
std;
}
Závěr.
Probrali jsme alternativní metody přístupu k identifikátoru z oboru názvů. Ve všech případech se vyhněte importování celých jmenných prostorů do zdrojového kódu.
Ačkoli osvojení a rozvoj správných kódovacích postupů může zabrat nějaký čas, z dlouhodobého hlediska se zpravidla vyplatí. Psaní čistého, jednoznačného a robustního kódu bez chyb by mělo být záměrem každého programátora.
Napsat komentář