Prohlášení pomocí jmenného prostoru std je obecně považována za špatnou praxi. Alternativou k tomuto příkazu je specifikovat jmenný prostor, do kterého identifikátor patří, pomocí operátoru oboru(::) pokaždé, když deklarujeme typ.
I když nás výpis ušetří psaní std:: kdykoli chceme přistupovat ke třídě nebo typu definovanému v jmenném prostoru std, importuje se celý std jmenný prostor do aktuálního jmenného prostoru programu. Uveďme si několik příkladů, abychom pochopili, proč to nemusí být tak dobré
Řekněme, že chceme použít cout ze jmenného prostoru std. Takže píšeme
Příklad 1:
CPP
#include> using> namespace> std;> > cout <<>' Something to Display'>;> |
>
>
Nyní v pozdější fázi vývoje chceme použít jinou verzi cout, která je vlastní implementována v nějaké knihovně zvané foo (například)
CPP
#include> #include> using> namespace> std;> > cout <<>' Something to display'>;> |
>
>
Všimněte si, že nyní existuje nejednoznačnost, na kterou knihovnu cout ukazuje? Kompilátor to může zjistit a nezkompilovat program. V nejhorším případě se program může přesto zkompilovat, ale zavolá špatnou funkci, protože jsme nikdy nespecifikovali, do kterého jmenného prostoru identifikátor patří.
Pro řešení konfliktů jmen identifikátorů byly do C++ zavedeny jmenné prostory. To zajistilo, že dva objekty mohou mít stejné jméno, a přesto s nimi lze zacházet odlišně, pokud patřily do různých jmenných prostorů. Všimněte si, jak v tomto příkladu došlo k pravému opaku. Místo řešení konfliktu jmen ve skutečnosti vytváříme konflikt jmen.
Když importujeme jmenný prostor, v podstatě stahujeme všechny definice typů do aktuálního rozsahu. Jmenný prostor std je obrovský. Má stovky předdefinovaných identifikátorů, takže je možné, že vývojář přehlédne skutečnost, že v knihovně std existuje jiná definice jejich zamýšleného objektu. Aniž by si toho byli vědomi, mohou přistoupit ke specifikaci vlastní implementace a očekávat, že bude použita v pozdějších částech programu. V aktuálním jmenném prostoru by tedy existovaly dvě definice pro stejný typ. To není v C++ povoleno, a i když se program zkompiluje, neexistuje způsob, jak zjistit, která definice se kde používá.
Řešením problému je explicitně specifikovat, do kterého jmenného prostoru náš identifikátor patří, pomocí operátoru oboru (::). Jedním z možných řešení výše uvedeného příkladu tedy může být
CPP
#include> #include> > // Use cout of std library> std::cout <<>'Something to display'>;> > // Use cout of foo library> foo::cout <>'Something to display'>;> |
>
>
Ale musí se psát std:: pokaždé, když definujeme typ, je únavné. Také díky tomu vypadá náš kód chlupatěji se spoustou definic typů a ztěžuje čtení kódu. Vezměme si například kód pro získání aktuálního času v programu
Příklad 2:
CPP
#include> #include> > auto> start = std::chrono::high_performance_clock::now()> > // Do Something> > auto> stop> >= std::chrono::high_peformance_clock::now();> auto> duration> >= std::duration_cast(stop - start);> |
>
>
Zdrojový kód, který je posetý složitými a dlouhými definicemi typů, není příliš dobře čitelný. To je něco, čemu se vývojáři snaží vyhnout, protože udržovatelnost kódu je pro ně především důležitá.
Existuje několik způsobů, jak vyřešit toto dilema, tj. zadat přesný jmenný prostor bez zahazování kódu pomocí standardních klíčových slov.
Zvažte použití typedefs
typedefs nás ušetří psaní dlouhých definic typů. V našem příkladu 1 bychom mohli problém vyřešit pomocí dvou typedefs, jeden pro knihovnu std a druhý pro foo
CPP
#include> #include> > typedef> std::cout cout_std;> typedef> foo::cout cout_foo;> > cout_std <<>'Something to write'>;> cout_foo <<>'Something to write'>;> |
>
>
Namísto importu celých oborů názvů importujte zkrácený obor názvů
V příkladu 2 jsme mohli importovat pouze jmenný prostor chrono pod std.
CPP
řetězec do pole java
#include> #include> > // Import only the chrono namespace under std> using> std::chrono;> > auto> start = high_performance_clock::now();> > // Do Something> auto> stop = high_performance_clock::now();> auto> duration duration_cast(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 stále importujete celé jmenné prostory, zkuste tak učinit uvnitř funkcí nebo omezeného rozsahu a ne v globálním rozsahu.
Použijte příkaz std using namespace uvnitř definic funkcí nebo definic tříd, struktur. Při tom se definice jmenného prostoru importují do místního oboru a my alespoň víme, kde mohou vzniknout možné chyby, pokud k nim dojde.
CPP
#include> > // Avoid this> using> namespace> std;> > void> foo()> {> >// Inside function> >// Use the import statement inside limited scope> >using> namespace> std;> > >// Proceed with function> }> |
>
>
Závěr.
Probrali jsme alternativní metody pro přístup k identifikátoru z jmenného prostoru. Ve všech případech se vyhněte importu celých jmenných prostorů do zdrojového kódu.
I když osvojení a vývoj správných kódovacích postupů může nějakou dobu trvat, obecně se z dlouhodobého hlediska 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átorského vývojáře.