Wydaje się, że istnieją różne poglądy na temat używania „using” w odniesieniu do standardowej przestrzeni nazw.
Niektórzy mówią używaj ' using namespace std
', inni mówią `` nie ' ', ale raczej prefiksuj funkcje standardowe, które mają być używane z ' std::
', podczas gdy inni mówią, że użyj czegoś takiego:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
dla wszystkich funkcji std, które mają być używane.
Jakie są zalety i wady każdego z nich?
c++
namespaces
paoloricardo
źródło
źródło
Odpowiedzi:
Większość użytkowników C ++ jest całkiem zadowolona z czytania
std::string
,std::vector
itp. W rzeczywistości, widok surowego plikuvector
sprawia, że zastanawiam się, czy to jeststd::vector
zdefiniowany przez użytkownika, czy innyvector
.Jestem zawsze przeciwko używaniu
using namespace std;
. Importuje wszystkie rodzaje nazw do globalnej przestrzeni nazw i może powodować różnego rodzaju nieoczywiste niejasności.Oto kilka typowych identyfikatorów w
std
przestrzeni nazw: count, sort, find, equal, reverse. Posiadanie zmiennej lokalnej o nazwiecount
oznacza, żeusing namespace std
nie będzie można jej użyćcount
zamiaststd::count
.Klasyczny przykład niechcianego konfliktu nazw jest podobny do następującego. Wyobraź sobie, że jesteś początkującym i nie wiesz o tym
std::count
. Wyobraź sobie, że albo używasz czegoś innego,<algorithm>
albo zostało to wciągnięte przez pozornie niepowiązany nagłówek.Błąd jest zwykle długi i nieprzyjazny, ponieważ
std::count
jest to szablon z kilkoma długimi zagnieżdżonymi typami.Jest to jednak w porządku, ponieważ
std::count
przechodzi do globalnej przestrzeni nazw, a funkcja count ją ukrywa.Być może trochę zaskakujące, to jest OK. Identyfikatory zaimportowane do zakresu deklaratywnego pojawiają się we wspólnej przestrzeni nazw, która obejmuje zarówno miejsce, w którym są zdefiniowane, jak i miejsce, w którym są importowane. Innymi słowy,
std::count
jest widoczny jakcount
w globalnej przestrzeni nazw, ale tylko wewnątrzincrement
.I z podobnych powodów
count
jest tutaj niejednoznaczny.using namespace std
nie powodujestd::count
, ukryj zewnętrzną,count
jak można się spodziewać. Teusing namespace
środki zasada, żestd::count
wygląd (wincrement
funkcji) tak, jakby to była zadeklarowana w zakresie globalnym, czyli w tym samym zakresie, jakint count = 0;
i tym samym powoduje niejasności.źródło
using std::xxx;
. Nie zanieczyszcza przestrzeni nazw, pisanie kodu będzie krótsze i myślę, żecopy
jest o wiele bardziej czytelne niżstd::copy
.Wykluczenie podstaw (Konieczność dodania std :: infront wszystkich obiektów / funkcji stl i mniejsza szansa na konflikt, jeśli nie masz opcji `` using namespace std '')
Warto również zauważyć, że nigdy nie powinieneś wkładać
W pliku nagłówkowym, ponieważ może propagować się do wszystkich plików, które zawierają ten plik nagłówkowy, nawet jeśli nie chcą używać tej przestrzeni nazw.
W niektórych przypadkach bardzo korzystne jest używanie takich rzeczy jak
Jakby istniała wyspecjalizowana wersja swapu, kompilator użyje jej, w przeciwnym razie powróci
std::swap
.Jeśli dzwonisz
std::swap
, zawsze używasz wersji podstawowej, która nie wywoła wersji zoptymalizowanej (jeśli istnieje).źródło
using std::swap
(co jest jedyną rzeczą, której kiedykolwiek używam).u n s
może się rozprzestrzeniać. Wystarczy zauważyć, że może on również przedostać się do poprawnie skonstruowanych nagłówków: wystarczy je dołączyć po nieuczciwym nagłówku.swap
lubmove
(lubhash
,less
itd.), Specjalizację, powinno być wprowadzenie tej specjalizacji wnamespace std
każdym razie. Na przykład:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
Najpierw trochę terminologii:
using std::vector;
using namespace std;
Myślę, że używanie dyrektyw using jest w porządku, o ile nie są one używane w globalnym zakresie w pliku nagłówkowym. Więc mając
w twoim pliku .cpp nie jest tak naprawdę problemem, a jeśli okaże się, że tak jest, jest całkowicie pod twoją kontrolą (i można go nawet przypisać do konkretnych bloków, jeśli chcesz). Nie widzę żadnego szczególnego powodu, aby zaśmiecać kod
std::
mnóstwem kwalifikatorów - staje się to po prostu kupą wizualnego szumu. Jeśli jednakstd
w swoim kodzie nie używasz całej grupy nazw z przestrzeni nazw, nie widzę problemu z pominięciem dyrektywy. To tautologia - jeśli dyrektywa nie jest konieczna, nie ma potrzeby jej używać.Podobnie, jeśli możesz sobie poradzić z kilkoma deklaracjami using (zamiast using-directives ) dla określonych typów w
std
przestrzeni nazw, to nie ma powodu, dla którego nie powinieneś mieć tylko tych spefcific nazw przenoszonych do bieżącej przestrzeni nazw. Z tego samego powodu myślę, że byłoby szalone i kłopotliwe z księgowością mieć 25 lub 30 deklaracji using, podczas gdy pojedyncza dyrektywa using równie dobrze wystarczyłaby.Warto również pamiętać, że czasami trzeba użyć deklaracji using. Zapoznaj się z „Punkt 25: Rozważ obsługę wymiany bez rzucania” Scotta Meyersa z Effective C ++, wydanie trzecie. Aby ogólna funkcja oparta na szablonie używała `` najlepszej '' metody zamiany dla typu sparametryzowanego, musisz użyć deklaracji użycia i wyszukiwania zależnego od argumentów (aka ADL lub Koenig lookup):
Myślę, że powinniśmy przyjrzeć się popularnym idiomom dla różnych języków, które w znacznym stopniu wykorzystują przestrzenie nazw. Na przykład Java i C # używają w dużym stopniu przestrzeni nazw (prawdopodobnie bardziej niż C ++). Najpopularniejszym sposobem używania nazw w przestrzeniach nazw w tych językach jest masowe przenoszenie ich do obecnego zakresu za pomocą odpowiednika dyrektywy using. Nie powoduje to powszechnych problemów, a kilka przypadków jest obsługiwanych na zasadzie „wyjątków”, zajmując się nazwami, o których mowa, za pomocą w pełni kwalifikowanych nazw lub aliasów - tak jak można to zrobić w C ++.
Herb Sutter i Andrei Alexandrescu mają to do powiedzenia w „Punkcie 59: Nie zapisuj użycia przestrzeni nazw w pliku nagłówkowym lub przed #include” w swojej książce C ++ Coding Standards: 101 Rules, Guidelines, and Best Practices:
Stroupstrup jest często cytowany jako powiedzenie „Nie zanieczyszczaj globalnej przestrzeni nazw” w „Języku programowania C ++, wydanie trzecie”. Faktycznie mówi to (C.14 [15]), ale odsyła do rozdziału C.10.1, w którym mówi:
A jak można mieć tę samą przewagę jako „leniwy użytkownik globalnych nazw”? Korzystając z dyrektywy using, która bezpiecznie udostępnia nazwy w przestrzeni nazw dla bieżącego zakresu.
Zauważ, że istnieje różnica - nazwy w
std
przestrzeni nazw udostępniane zakresowi z odpowiednim użyciem dyrektywy using (umieszczając dyrektywę po niej#includes
) nie zanieczyszczają globalnej przestrzeni nazw. Po prostu ułatwia dostęp do tych nazw i zapewnia ciągłą ochronę przed kolizjami.źródło
std::
kwalifikatory nie zaśmiecały kodu - są inne sposoby, aby tego uniknąć (użycie-deklaracji lub typedefs zwykle załatwia sprawę).using namespace std;
dyrektywy „ ” nie przeszkadza w zadeklarowaniu swojego naturalnego identyfikatoralist
”- po prostu jeśli to zrobisz, nie możesz nie dłuższe użytkowaniestd::list
bez kwalifikacji. Nie różni się to od tego, "using namespace std;
" jeśli nie ma dyrektywy. A może coś mi brakuje?Nigdy nie używaj przestrzeni nazw w zasięgu globalnym w pliku nagłówkowym. Może to prowadzić do konfliktu, a osoba odpowiedzialna za plik, w którym występuje konflikt, nie ma kontroli nad przyczyną.
W pliku implementacji wybory są znacznie trudniejsze.
Wstawienie używającego standardu przestrzeni nazw powoduje pobranie wszystkich symboli z tych przestrzeni nazw. Może to być kłopotliwe, ponieważ prawie żaden organizm nie zna wszystkich symboli, które tam są (więc polityka braku konfliktu jest niemożliwa do zastosowania w praktyce) bez mówienia o symbolach, które zostaną dodane. A standard C ++ pozwala nagłówkowi na dodawanie symboli z innych nagłówków (C nie pozwala na to). Nadal może dobrze działać w praktyce, aby uprościć pisanie w kontrolowanych przypadkach. A jeśli wystąpi błąd, zostanie wykryty w pliku, którego dotyczy problem.
Umieszczanie za pomocą std :: name; ma tę zaletę, że jest prosty w pisaniu bez ryzyka importowania nieznanych symboli. Koszt jest taki, że musisz jawnie zaimportować wszystkie potrzebne symbole.
Wyraźne kwalifikacje dodają trochę bałaganu, ale myślę, że jest to mniej kłopotliwe w przypadku niektórych ćwiczeń.
W moim projekcie używam jawnej kwalifikacji dla wszystkich nazw, akceptuję użycie std :: name, walczę z używaniem std przestrzeni nazw (mamy interpreter lisp, który ma swój własny typ listy, więc konflikt jest pewny).
W przypadku innych przestrzeni nazw należy również wziąć pod uwagę stosowane konwencje nazewnictwa. Znam projekt, który używa przestrzeni nazw (do wersjonowania) i prefiksu w nazwach. Wykonanie a
using namespace X
następnie jest prawie bez ryzyka, a nie wykonanie tego prowadzi do głupiego wyglądu koduPrefixNS::pfxMyFunction(...)
.W niektórych przypadkach chcesz zaimportować symbole. std :: swap jest najczęstszym przypadkiem: importujesz std :: swap, a następnie używasz swap unqualified. Wyszukiwanie zależne od argumentów znajdzie odpowiednią zamianę w przestrzeni nazw typu, jeśli taki istnieje, i powróci do standardowego szablonu, jeśli go nie ma.
Edytować:
W komentarzach Michael Burr zastanawia się, czy konflikty mają miejsce w prawdziwym świecie. Oto prawdziwy przykład na żywo. Mamy rozszerzenie języka z dialektem lisp. Nasz interpreter ma plik dołączania lisp.h zawierający
Musieliśmy zintegrować i zaadaptować kod (który nadam nazwę „silnik”), który wyglądał następująco:
Więc zmodyfikowaliśmy w ten sposób:
Dobry. Wszystko działa. Kilka miesięcy później plik „module.h” został zmodyfikowany i zawierał „list.h”. Testy zdały. „Moduł” nie został zmodyfikowany w sposób, który wpłynąłby na jego ABI, więc biblioteka „silnika” mogła być używana bez ponownej kompilacji jego użytkowników. Testy integracyjne wypadły OK. Opublikowano nowy „moduł”. Następna kompilacja silnika zepsuła się, gdy jego kod nie został zmodyfikowany.
źródło
Jeśli nie masz ryzyka konfliktów nazw w swoim kodzie z bibliotekami standardowymi i innymi, możesz użyć:
Ale jeśli chcesz dokładnie poznać zależność twojego kodu od dokumentacji lub istnieje ryzyko konfliktu nazw, użyj innego sposobu:
Trzecie rozwiązanie, nie korzystaj z tych rozwiązań i napisz std :: przed każdym użyciem w kodzie zapewnia większe bezpieczeństwo, ale może trochę ciężko w kodzie ...
źródło
Obie
i
dodać kilka symboli (jeden lub wiele) do globalnej przestrzeni nazw. A dodawanie symboli do globalnej przestrzeni nazw jest czymś, czego nigdy nie powinieneś robić w plikach nagłówkowych. Nie masz kontroli, kto będzie zawierał twój nagłówek, istnieje wiele nagłówków, które zawierają inne nagłówki (i nagłówki, które zawierają nagłówki zawierające nagłówki i tak dalej ...).
W przypadku plików implementacji (.cpp) to zależy od Ciebie (pamiętaj tylko, aby zrobić to po wszystkich dyrektywach #include). Możesz złamać tylko kod w tym konkretnym pliku, więc łatwiej jest zarządzać i znaleźć przyczynę konfliktu nazw. Jeśli wolisz używać std :: (lub dowolnego innego prefiksu, w projekcie może być wiele przestrzeni nazw) przed indentyfikatorami, jest OK. Jeśli chcesz dodać identyfikatory, których używasz do globalnej przestrzeni nazw, jest OK. Jeśli chcesz wnieść na głowę całą przestrzeń nazw :-), to zależy od Ciebie. Chociaż efekty są ograniczone do jednej jednostki kompilacji, jest to akceptowalne.
źródło
Dla mnie wolę używać,
::
gdy to możliwe.Nienawidzę pisać:
Mam nadzieję, że w C ++ 0x napisałbym to:
Jeśli przestrzeń nazw jest bardzo długa,
źródło
++i
, a niei++
dlatego, że jeśli jest nawet zdefiniowane, tworzy niepotrzebną tymczasową kopię iteratora.Nigdy nie powinieneś znajdować się
using namespace std
w zakresie przestrzeni nazw w nagłówku. Przypuszczam też, że większość programistów będzie się zastanawiać, kiedy zobacząvector
lubstring
bezstd::
, więc myślę, że nieusing namespace std
jest lepiej. Dlatego twierdzę, że nigdy nie będzieusing namespace std
.Jeśli czujesz, że musisz, dodaj lokalne deklaracje, takie jak
using std::vector
. Ale zadaj sobie pytanie: ile to jest warte? Linia kodu jest zapisywana raz (może dwa razy), ale jest czytana dziesięć, sto lub tysiące razy. Oszczędny wysiłek związany z pisaniem, wynikający z dodania deklaracji using lub dyrektywy, jest marginalny w porównaniu z wysiłkiem związanym z odczytaniem kodu.Mając to na uwadze, w projekcie sprzed dziesięciu lat zdecydowaliśmy się jawnie zakwalifikować wszystkie identyfikatory ich pełnymi nazwami przestrzeni nazw. To, co początkowo wydawało się niezręczne, w ciągu dwóch tygodni stało się rutyną. Teraz we wszystkich projektach tej całej firmy nikt już nie używa dyrektyw ani deklaracji. (Z jednym wyjątkiem, patrz poniżej). Patrząc na kod (kilka MLoC) po dziesięciu latach, mam wrażenie, że podjęliśmy właściwą decyzję.
Zauważyłem, że zazwyczaj ci, którzy są przeciwni banowaniu,
using
zwykle nie próbowali tego w przypadku jednego projektu. Ci, którzy próbowali, często uważają to za lepsze niż używanie dyrektyw / deklaracji po bardzo krótkim czasie.Uwaga: Jedynym wyjątkiem jest to,
using std::swap
co jest konieczne (szczególnie w kodzie ogólnym), aby odebrać przeciążeniaswap()
, których nie można umieścić wstd
przestrzeni nazw (ponieważ nie możemy umieszczać przeciążeństd
funkcji w tej przestrzeni nazw).źródło
std
, ale nie przeciążam ich. Przepraszam za to bzdury. Poprawię post.using namespace
dyrektywy było stworzenie wpisywanie albo; chodziło raczej o ułatwienie czytania , ponieważ, jak mówisz, ten kod będzie musiał być czytany dziesiątki, setki lub tysiące razy. A dla niektórych osób czyta się znacznie łatwiej i jest mniejstd::
bałaganu. Ale to prawdopodobnie sprowadza się do osobistych zdolności percepcyjnych; niektórzy ludzie odfiltrowująstd::
go lub nawet potrzebują go jako wskazówki (jak szeryfy), inni potykają się na nim i czują się jak na wyboistej drodze.Przestrzenie nazw zawierają kod, aby zapobiec pomyłkom i zanieczyszczeniu sygnatur funkcji.
Oto kompletne i udokumentowane demo prawidłowego wykorzystania przestrzeni nazw :
Wynik:
źródło
using namespace std
importuje zawartośćstd
przestrzeni nazw w bieżącej. W związku z tym zaletą jest to, że nie musisz wpisywaćstd::
przed wszystkimi funkcjami tej przestrzeni nazw. Jednak może się zdarzyć, że masz różne przestrzenie nazw, które mają funkcje o tej samej nazwie. Dlatego możesz przestać dzwonić do tego, którego chcesz.Ręczne określenie, które z nich chcesz importować,
std
zapobiega temu, ale może skutkować długą listą użycia na początku pliku, co niektórzy deweloperzy uznają za brzydkie;)!Osobiście wolę określać przestrzeń nazw za każdym razem, gdy używam funkcji, z wyjątkiem sytuacji, gdy przestrzeń nazw jest zbyt długa, w którym to przypadku umieszczam użycie na początku pliku.
EDYCJA: jak zauważono w innej odpowiedzi, nigdy nie należy umieszczać a
using namespace
w pliku nagłówkowym, ponieważ będzie on propagował się do wszystkich plików, w tym tego nagłówka, i może powodować niepożądane zachowanie.EDIT2: poprawiłem moją odpowiedź, dzięki komentarzowi Charlesa.
źródło
using namespace std;
importuje zawartośćstd
przestrzeni nazw do globalnej przestrzeni nazw. Nie zmienia domyślnej przestrzeni nazw. Zdefiniowanie czegoś w globalnej przestrzeni nazw po ausing namespace std
nie w magiczny sposób umieści to wstd
przestrzeni nazw.Podobnie jak w Javie, gdzie możesz użyć java.util. * Lub po prostu wybrać każdą klasę indywidualnie, zależy to od stylu. Zauważ, że nie chcesz, aby znajdował się on
using namespace std
na początku twojego pliku / szerokiego zakresu, ponieważ zanieczyszczasz przestrzeń nazw i prawdopodobnie będziesz mieć konflikty, pokonując punkt przestrzeni nazw. Ale jeśli masz funkcję, która używa dużo STL, zaśmieca ona kod, aby mieć mieszankę składni prefiksów w twojej logice i prawdopodobnie powinieneś rozważyć użycie albousing namespace std
(jeśli używasz różnych klas), albo pojedynczychusing
s (używając kilku zajęcia często).źródło
Ta dyskusja będzie żyła, o ile IDE, z którym pracujesz, nie będzie wystarczająco elastyczne, aby pokazać lub ukryć dokładne informacje, których potrzebujesz.
Dzieje się tak, ponieważ to, jak ma wyglądać kod, zależy od wykonywanego zadania.
Podczas tworzenia kodu źródłowego wolę dokładnie sprawdzić, której klasy używam: czy to jest
std::string
, czyBuzFlox::Obs::string
klasa klasa?Projektując przepływ sterowania, nie interesują mnie nawet typy zmiennych, ale chcę skupić się na
if
„iwhile
” orazcontinue
„s”.Więc to jest moja rada:
W zależności od odbiorców twojego kodu i możliwości twoich narzędzi, wybierz sposób, który albo czyta go najłatwiej, albo dostarcza najwięcej informacji.
źródło
Istnieje kilka sposobów, aby to naprawić.
Po pierwsze: używaj tak, jak zrobiłeś.
Po drugie: zrób
namespace S = std;
, zmniejszając 2 znaki.Po trzecie: użyj
static
.Po czwarte: nie używaj nazw, które
std
używają.źródło
Jedynym powodem, dla którego należy pominąć std :: jest to, że teoretycznie można samodzielnie zreimplementować wszystkie funkcje STL. Wtedy funkcje można by przełączyć z używania std :: vector na my :: vector bez zmiany kodu.
źródło
Dlaczego nie na przykład
zamiast nieporęcznego
Uważam, że jest to znacznie bardziej czytelne i jest to mój standard kodowania.
Możesz nawet użyć go do dołączenia pewnych informacji semantycznych dla czytelnika. Na przykład rozważmy prototypy funkcji
które z nich zwracają wartość?
A może zamiast tego
źródło