Dlaczego „używa przestrzeni nazw std;” uważane za złą praktykę?


2639

Powiedziano mi przez innych, że pisanie using namespace std;w kodzie jest źle, i że powinno się używać std::couti std::cinbezpośrednio zamiast.

Dlaczego using namespace std;uważa się za złą praktykę? Czy jest nieefektywny, czy ryzykuje zadeklarowanie niejednoznacznych zmiennych (zmiennych o tej samej nazwie co funkcja w stdprzestrzeni nazw)? Czy wpływa to na wydajność?


512
Nie zapomnij, że możesz: „using std :: cout;” co oznacza, że ​​nie musisz wpisywać std :: cout, ale nie wprowadzaj całej przestrzeni nazw std w tym samym czasie.
Bill

2
@ płatny nerd google-styleguide.googlecode.com/svn/trunk/… link już nie działa. Wygląda na to, że nowy link to google.github.io/styleguide/cppguide.html#Other_C++_Features
MCG

64
Szczególnie źle jest używać opcji „using namespace std” w zakresie plików w plikach nagłówkowych. Używanie go w plikach źródłowych (* .cpp) w zakresie plików nie jest wcale takie złe, ponieważ jego działanie jest ograniczone do jednej jednostki tłumaczeniowej. Jeszcze mniej problematyczne jest używanie go w funkcjach lub klasach, ponieważ jego działanie jest ograniczone do zakresu funkcji lub klasy.
sh-

5
Chciałbym zniechęcać do korzystania za pomocą dyrektywy, ale dla konkretnych nazw podoba std::literals::chrono_literals, Poco::Data:Keywords, Poco::Unitsa rzeczy, które będą zajmować się literałów lub sztuczek czytelność. Ilekroć znajduje się w plikach nagłówka lub implementacji. Wydaje mi się, że może być OK w zakresie funkcji, ale oprócz literałów i innych rzeczy nie jest to przydatne.
Ludovic Zenohate Lagouardette,

7
@Jon: W szczególności nie ma to nic wspólnego z przestrzenią nazw. Mój nacisk miał być położony na „w zakresie plików w plikach nagłówkowych”. Ujmując to jako poradę: Nie używaj „using namespace” (std lub inny) w zakresie plików w plikach nagłówkowych. Można używać go w plikach implementacyjnych. Przepraszam za dwuznaczność.
sh-

Odpowiedzi:


2229

W ogóle nie ma to związku z wydajnością. Ale zastanów się: używasz dwóch bibliotek o nazwach Foo i Bar:

using namespace foo;
using namespace bar;

Wszystko działa dobrze i bez problemu możesz dzwonić Blah()z Foo i Quux()Bar. Ale pewnego dnia zaktualizujesz do nowej wersji Foo 2.0, która teraz oferuje funkcję o nazwie Quux(). Teraz masz konflikt: Zarówno Foo 2.0, jak i Bar importują się Quux()do Twojej globalnej przestrzeni nazw. Będzie to wymagać pewnego wysiłku, aby naprawić, szczególnie jeśli parametry funkcji się zgadzają.

Gdybyś użył foo::Blah()i bar::Quux(), to wprowadzenie foo::Quux()byłoby nie-wydarzeniem.


435
Zawsze podobało mi się, że Python „import big_honkin_name as bhn”, więc możesz po prostu użyć „bhn.something” zamiast „big_honkin_name.something” - naprawdę ogranicza pisanie. Czy C ++ ma coś takiego?
paxdiablo

764
@Pax namespace io = boost :: filesystem;
AraK

152
Myślę, że przesadą jest stwierdzenie, że jest to „pewien wysiłek do naprawienia”. Nie będziesz mieć instancji nowego foo :: Quux, więc po prostu ujednoznacznij wszystkie obecne zastosowania z bar :: Quux.
MattyT,

289
Czy jakakolwiek rozsądna osoba stworzyłaby bibliotekę z typami, których niekwalifikowana nazwa koliduje z typami standardowymi?
erikkallen

94
@TomA: Problem #definepolega na tym, że nie ogranicza się do przestrzeni nazw, ale depcze po całej bazie kodu. Alias ​​przestrzeni nazw jest tym, czego chcesz.
sbi

1390

Zgadzam się ze wszystkim, co napisał Greg , ale chciałbym dodać: Może być nawet gorzej niż powiedział Greg!

Biblioteka Foo 2.0 mogłaby wprowadzić funkcję, Quux()która jest jednoznacznie lepsza dla niektórych twoich wywołań Quux()niż bar::Quux()kod wywoływany przez lata. Wtedy twój kod wciąż się kompiluje , ale po cichu wywołuje niewłaściwą funkcję i robi Bóg-wie-co. To jest tak złe, jak tylko się da.

Należy pamiętać, że stdprzestrzeń nazw ma mnóstwo identyfikatorów, z których wiele jest bardzo spotykane (myślę list, sort, string, iterator, itd.), Które są bardzo prawdopodobne, aby pojawić się w innym kodem, too.

Jeśli uważasz, że jest to mało prawdopodobne: na przepełnieniu stosu pojawiło się pytanie , w którym dokładnie to się stało (zła funkcja została wywołana z powodu pominiętego std::prefiksu) około pół roku po udzieleniu tej odpowiedzi. Oto kolejny, bardziej aktualny przykład takiego pytania. To jest prawdziwy problem.


Oto jeszcze jeden punkt danych: wiele, wiele lat temu uważałem, że denerwujące jest to, że muszę poprzedzać wszystko standardową biblioteką std::. Potem pracowałem nad projektem, w którym na początku zdecydowano, że zarówno usingdyrektywy, jak i deklaracje są zakazane, z wyjątkiem zakresów funkcji. Zgadnij co? Większość z nas zajęło kilka tygodni przyzwyczajenie się do pisania prefiksu, a po kilku kolejnych tygodniach większość z nas nawet zgodziła się, że w rzeczywistości kod jest bardziej czytelny . Jest po temu powód: to, czy lubisz krótszą czy dłuższą prozę, jest subiektywne, ale przedrostki obiektywnie zwiększają przejrzystość kodu. Nie tylko kompilator, ale i Ty łatwiej jest sprawdzić, do którego identyfikatora się odnosi.

W ciągu dekady ten projekt urósł do kilku milionów wierszy kodu. Ponieważ dyskusje te pojawiają się wielokrotnie, raz byłem ciekawy, jak często (dozwolony) zakres funkcji usingfaktycznie był używany w projekcie. Przeszukałem źródła i znalazłem tylko jeden lub dwa tuziny miejsc, w których był używany. Dla mnie oznacza to, że po wypróbowaniu programiści nie są na std::tyle bolesni, by stosować dyrektywy nawet raz na każde 100 kLoC, nawet jeśli pozwolono na ich użycie.


Konkluzja: Jawne prefiksowanie wszystkiego nie wyrządza żadnej szkody, przyzwyczaja się bardzo mało i ma obiektywne zalety. W szczególności ułatwia interpretację kodu przez kompilator i czytelników - i to prawdopodobnie powinno być głównym celem podczas pisania kodu.


140
Znacząco szkodzi to gęstości kodu, który można spakować w jednym wierszu. W końcu piszesz swój kod w bardzo rozwlekły sposób; co zmniejsza czytelność. Osobiście uważam, że krótszy (ale nie za krótki) kod jest zazwyczaj bardziej czytelny (ponieważ jest mniej rzeczy do przeczytania i mniej rzeczy do rozproszenia).
Lie Ryan,

91
Chyba przegapiłeś dawne czasy, zanim C ++ miał standardową stringklasę i najwyraźniej każda biblioteka miała swoją własną. Powiem ci, co: będziemy dalej pisać nasz kod std::i możesz go przepuszczać grep -v std:: | vimpodczas przeglądania. Możesz też nauczyć swojego edytora, że std::jest słowem kluczowym, które ma być tak samo kolorowe, jak kolor tła. Cokolwiek działa.
Mike DeSimone

79
Nie wydaje mi się, żeby std::był szkodliwy. Zawiera bardzo ważne informacje (a mianowicie „to, co nastąpi później, jest częścią standardowej biblioteki”, i wciąż jest dość krótkim i zwartym prefiksem. Przez większość czasu nie stanowi to żadnego problemu. Czasami masz kilka linii kodu gdzie trzeba stdczęsto odwoływać się do określonych symboli w przestrzeni nazw, a następnie usingstwierdzenie w tym konkretnym zakresie ładnie rozwiązuje problem. Ale w ogólnym przypadku nie jest to hałas, przekazuje cenne informacje oprócz usuwania dwuznaczności.
jalf

146
Ilekroć to widzę std::, wiem, że to będzie std::bez zastanowienia. Jeśli widzę stringlub listlub mapprzez siebie, zastanawiam się trochę.
Mateen Ulhaq

67
@LieRyan Następnie powodzenia napisanie biblioteki geometrii bez nazywania kiedykolwiek coś vector, transformalbo distance. A to tylko przykłady wielu bardzo popularnych nazw używanych w standardowej bibliotece. Sugerowanie, aby nie używać ich ze strachu lub stronnicze opinie na temat funkcji przestrzeni nazw, która jest integralną częścią C ++, przynosi efekt przeciwny do zamierzonego.
Christian Rau,

419

Problem z umieszczaniem using namespacew plikach nagłówkowych twoich klas polega na tym, że zmusza każdego, kto chce użyć twoich klas (włączając pliki nagłówkowe), by również „używały” (tj. Widziały wszystko w) tych innych przestrzeniach nazw.

Możesz jednak umieścić instrukcję using w swoich (prywatnych) plikach * .cpp.


Strzeż się, że niektórzy nie zgadzają się z moim powiedzeniem „czuj się swobodnie” w ten sposób - ponieważ chociaż usingoświadczenie w pliku cpp jest lepsze niż w nagłówku (ponieważ nie dotyczy to osób, które zawierają plik nagłówka), myślą, że nadal nie jest dobry (ponieważ w zależności od kodu może to utrudnić utrzymanie implementacji klasy). Ten wpis C ++ Super-FAQ mówi:

Dyrektywa use istnieje dla starszego kodu C ++ i dla ułatwienia przejścia do przestrzeni nazw, ale prawdopodobnie nie powinieneś go używać regularnie, przynajmniej nie w nowym kodzie C ++.

FAQ sugeruje dwie alternatywy:

  • Deklaracja użycia:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
  • Po prostu wpisuję std ::

    std::cout << "Values:";

1
Oczywiście, nigdy nie powinieneś zakładać stanu globalnego cout, aby ktoś nie miał std: cout << std :: hex i nie udało się później std :: restore_cout_state. Ale to zupełnie inna fatberga.
Móż

233

Niedawno spotkałem się ze skargą dotyczącą programu Visual Studio 2010 . Okazało się, że prawie wszystkie pliki źródłowe miały te dwie linie:

using namespace std;
using namespace boost;

Wiele funkcji Boost przechodzi do standardu C ++ 0x, a Visual Studio 2010 ma wiele funkcji C ++ 0x, więc nagle te programy się nie kompilowały.

Dlatego unikanie using namespace X;jest formą zabezpieczenia na przyszłość, sposobem upewnienia się, że zmiana używanych bibliotek i / lub plików nagłówkowych nie spowoduje uszkodzenia programu.


14
To. Rozbudowa i STD posiada wiele nakładania - zwłaszcza, że C ++ 11.
einpoklum

1
Zrobiłem to raz i nauczyłem się czegoś na własnej skórze. Teraz nigdy nie używam usingpoza definicją funkcji i rzadko używam using namespacew ogóle.
Ferruccio,

210

Wersja skrócona: nie używaj globalnych usingdeklaracji ani dyrektyw w plikach nagłówków. Używaj ich w plikach implementacyjnych. Oto, co Herb Sutter i Andrei Alexandrescu mają do powiedzenia na ten temat w standardach kodowania C ++ (pogrubienie dla podkreślenia jest moje):

Podsumowanie

Korzystanie z przestrzeni nazw jest dla Twojej wygody, a nie do narzucania innym: Nigdy nie pisz deklaracji użycia lub dyrektywy użytkowania przed dyrektywą #include.

Następstwo: w plikach nagłówkowych nie pisz na poziomie przestrzeni nazw przy użyciu dyrektyw lub deklaracji; zamiast tego jawnie kwalifikuj przestrzeń nazw wszystkie nazwy. (Druga reguła wynika z pierwszej, ponieważ nagłówki nigdy nie mogą wiedzieć, jakie inne nagłówki #include mogą się po nich pojawić).

Dyskusja

W skrócie: Możesz i powinieneś używać przestrzeni nazw, używając deklaracji i dyrektyw swobodnie w swoich plikach implementacyjnych po #include dyrektyw i dobrze się z tym czujesz. Pomimo powtarzających się twierdzeń przeciwnych, przestrzeń nazw z deklaracjami i dyrektywami nie jest zła i nie pokonuje celu przestrzeni nazw. Są raczej tym, co sprawia, że ​​przestrzenie nazw są użyteczne .


4
Jeszcze jedna opinia programisty tutaj, ale chociaż w 100% zgadzam się ze stwierdzeniem, że słowo usingnigdy nie powinno pojawiać się w nagłówku, nie jestem tak przekonany o bezpłatnej licencji na umieszczenie using namespace xyz;dowolnego miejsca w kodzie, szczególnie jeśli xyzjest std. Korzystam z tego using std::vector;formularza, ponieważ wyciąga on tylko jeden element z przestrzeni nazw do zakresu pseudoglobalnego, co prowadzi do znacznie mniejszego ryzyka kolizji.
dgnuff

2
@Lightness Races in Orbit, oczywiście masz prawo do swojej opinii. Byłoby bardziej pomocne, gdyby podjęto próbę wyjaśnienia, dlaczego nie zgadzasz się z poradami zawartymi w tej odpowiedzi. Szczególnie interesujące byłoby zrozumienie, jaki jest sens przestrzeni nazw, jeśli ich „używanie” jest złe? Dlaczego nie nazwać po prostu std_cout zamiast std :: cout ... twórcy C ++ / namespace musieli mieć pewien pomysł, kiedy starali się je stworzyć.
nyholku

1
@nyholku: Nie ma potrzeby - większość innych odpowiedzi podaje te same powody. Proszę również o zwrócenie uwagi na „:)” Dołączyłem do mojego komentarza! I że nie powiedziałem, że przestrzenie nazw są złe.
Wyścigi lekkości na orbicie

Tak, zauważyłem to :) ale IMO większość odpowiedzi (które są sprzeczne z tą radą mędrca) jest myląca (nie dlatego, że stworzyłem statystyki, co jest teraz większością). Jeśli zgadzasz się, że przestrzeń nazw jest „niezła”, możesz powiedzieć, gdzie uważasz, że są odpowiednie, jeśli nie zgadzasz się z tą odpowiedzią?
nyholku

Nie mogę nic poradzić, ale czuję, że using namespaceto zło gotojest jak zło. Oba mają prawidłowe zastosowania, ale 999 razy na 1000 będą niewłaściwie użyte. Tak, tak, using namespacew źródle nie będzie zanieczyszczać przestrzeni nazw innych włączników. Ale nadal nie ochroni cię przed „zabawą”, która powstaje z using namespace Foo+ using namespace Bar, gdy dzwonisz (domyślnie Foo: :) baz(xyz)i nagle łamie się kod (bez powiązanych zmian) tylko dlatego, że ponieważ Bar::baz()został gdzieś dodany, co akurat jest lepsze match (i dlatego teraz zostaje wywołany)
CharonX

122

Nie należy stosować usingdyrektywy w zakresie globalnym, szczególnie w nagłówkach. Są jednak sytuacje, w których jest to właściwe nawet w pliku nagłówkowym:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; // No problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

Jest to lepsze niż kwalifikacja jawna ( std::sin, std::cos...), ponieważ jest krótsze i ma możliwość pracy z typami zmiennoprzecinkowymi zdefiniowanymi przez użytkownika (za pomocą wyszukiwania zależnego od argumentów (ADL)).


9
Przepraszam, ale zdecydowanie się z tym nie zgadzam.
Billy ONeal,

4
@Billy: Nie ma innego sposobu na obsługę wywoływania userlib :: cos (userlib :: superint). Każda funkcja ma swoje zastosowanie.
Zan Lynx

17
@Zan: Oczywiście, że tak. using std::cos;, using std::sinitd. Problem polega jednak na tym, że każdy dobrze zaprojektowany userlibbędzie miał swoją własną przestrzeń nazw sini coswewnątrz niej, więc to naprawdę nie pomaga. (Chyba, że using namespace userlibprzed tym szablonem jest tak samo źle using namespace std- a jego zakres nie jest ograniczony.) Ponadto jedyną taką funkcją, jaką kiedykolwiek widziałem, jest swap, i w takich przypadkach zaleciłbym utworzenie szablonu specjalizacja std::swapi unikanie całego problemu.
Billy ONeal

11
@BillyONeal: template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)(Nie ma częściowej specjalizacji szablonu funkcji (FTPS), więc czasami trzeba zamiast tego uciekać się do przeciążania)
sbi

38
@BillyONeal: Twój (7-krotnie oceniany!) Komentarz jest błędny - opisywana przez ciebie sytuacja jest dokładnie tym , co ADL został zaprojektowany na pokrycie. W skrócie, jeśli xma co najmniej jedną „powiązaną przestrzeń nazw” (np. Jeśli została zdefiniowana w namespace userlib), wówczas każde wywołanie funkcji, które wygląda tak, cos(x)będzie dodatkowo wyglądać w tych przestrzeniach nazw - bez konieczności using namespace userlib;wcześniejszego. Zan Lynx ma rację (a wyszukiwanie nazw C ++ jest bizantyjskie ...)
j_random_hacker

97

Nie używaj go globalnie

Jest uważany za „zły” tylko wtedy, gdy jest używany globalnie . Ponieważ:

  • Zaśmiecasz przestrzeń nazw, w której programujesz.
  • Czytelnicy będą mieli trudności z ustaleniem, skąd pochodzi dany identyfikator, gdy używasz wielu using namespace xyz.
  • Cokolwiek jest prawdą dla innych czytelników twojego kodu źródłowego, jest jeszcze bardziej prawdziwe dla jego najczęstszego czytelnika: ciebie. Wróć za rok lub dwa i spójrz ...
  • Jeśli mówisz tylko o tym, using namespace stdmożesz nie być świadomy wszystkich rzeczy, które chwytasz - a gdy dodasz kolejną #includelub przejdziesz do nowej wersji C ++, możesz mieć konflikty nazw, o których nie wiedziałeś.

Możesz używać go lokalnie

Śmiało i używaj go lokalnie (prawie) swobodnie. To oczywiście zapobiega powtarzaniu się std::- a powtarzanie jest również złe.

Idiom używający go lokalnie

W C ++ 03 istniał idiom - kociołkowy kod - do implementacji swapfunkcji dla twoich klas. Zasugerowano, że faktycznie używasz lokalnego using namespace std- a przynajmniej 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(...)`
}

To robi następującą magię:

  • Kompilator wybierze std::swapfor value_, tj void std::swap(int, int).
  • Jeśli masz void swap(Child&, Child&)zaimplementowane przeciążenie, kompilator go wybierze.
  • Jeśli nie masz tego przeciążenia, kompilator użyje void std::swap(Child&,Child&)i spróbuje jak najlepiej zamienić je.

W C ++ 11 nie ma powodu, aby używać tego wzorca. Implementacja std::swapzostała zmieniona, aby znaleźć potencjalne przeciążenie i wybrać to.


5
„Implementacja std :: swap została zmieniona, aby znaleźć potencjalne przeciążenie i wybrać to.” - Co? Jesteś pewien? Chociaż prawdą jest, że dostarczenie niestandardowego kodu swapnie jest już tak ważne w C ++ 11, ponieważ std::swapsam w sobie jest bardziej elastyczny (używa semantyki ruchu). Ale std::swapautomatycznie wybieram własną niestandardową wymianę, co jest dla mnie absolutnie nowe (i tak naprawdę w to nie wierzę).
Christian Rau,

@ChristianRau Myślę, że tak, tak. Gdzieś to przeczytałem na SO. Zawsze możemy zapytać Howarda , powinien wiedzieć. Jestem kopanie i kopanie teraz ...
towi

14
Nawet w przypadku zamiany jaśniejszym (i na szczęście bardziej powszechnym) idiomem jest pisanie, using std::swap;a nie using namespace std;. Bardziej szczegółowy idiom ma mniej skutków ubocznych i dlatego sprawia, że ​​kod jest łatwiejszy w utrzymaniu.
Adrian McCarthy

11
Ostatnie zdanie jest złe. W C ++ 11 Std Swap Two Step został oficjalnie pobłogosławiony jako właściwy sposób na sprawdzenie swap, a różne inne miejsca w standardzie zostały zmienione, aby powiedzieć, że swaptak nazywają (NB, jak wspomniano powyżej, using std::swapjest właściwą drogą, a nie using namespace std). Ale std::swapsamo to nie zostało zdecydowanie zmienione, aby znaleźć inne swapi użyć go. Jeśli std::swapzostanie wywołany, wtedy std::swapsię przyzwyczai.
Jonathan Wakely

3
Mądrzejsze może być po prostu wpisanie using std::swaplokalne, aby zmniejszyć lokalną przestrzeń nazw, jednocześnie tworząc kod samokontrujący. Rzadko kiedy interesuje Cię cała przestrzeń nazw, więc po prostu wybierz części, którymi jesteś zainteresowany.
Lundin

79

Jeśli importujesz odpowiednie pliki nagłówkowe nagle mają nazwy jak hex, left, pluslub countw swoim zasięgu globalnym. Może to być zaskakujące, jeśli nie wiesz, że std::zawierają te nazwy. Jeśli spróbujesz także użyć tych nazw lokalnie, może to prowadzić do pewnych nieporozumień.

Jeśli wszystkie standardowe elementy znajdują się we własnej przestrzeni nazw, nie musisz się martwić o kolizje nazw z kodem lub innymi bibliotekami.


12
+1 nie wspominając distance. nadal wolę nazwy niekwalifikowane, o ile jest to praktycznie możliwe, ponieważ zwiększa to dla mnie czytelność. plus, myślę, że fakt, iż zwykle nie kwalifikujemy się do mówienia i jesteśmy gotowi poświęcić czas na rozwiązywanie ewentualnych niejasności, oznacza, że ​​warto zrozumieć, o czym mówi się bez kwalifikacji, i zastosować do źródła kod, który oznacza, że ​​jest skonstruowany w taki sposób, że jest jasne, o co w tym wszystkim chodzi, nawet bez kwalifikacji.
Pozdrawiam i hth. - Alf

Szczerze mówiąc, nie masz większości z nich, jeśli ich nie uwzględnisz <iomanip>. Nadal dobry punkt.
einpoklum

48

Kolejnym powodem jest niespodzianka.

Jeśli widzę cout << blah, zamiast std::cout << blahmyśleć: co to jest cout? Czy to normalne cout? Czy to jest coś specjalnego?


25
Czy to żart? Naprawdę nie mogę powiedzieć. Jeśli nie, to osobiście bym założył, że to normalne „cout”, chyba że nie ufasz kodowi, ponieważ w przeciwnym razie byłby to BEYOND MAJOR zapach, IMO. ... A jeśli nie ufasz kodowi, dlaczego go używasz? Zauważ, że nie mówię „ZAUFAJ WSZYSTKIM !!” ale wydaje się to również trochę za daleko, jeśli, powiedzmy, masz do czynienia z jakąś znaną biblioteką z GitHub lub coś takiego.
Brent Rittenhouse

28
@BrentRittenhouse coutjest złym przykładem, ponieważ wszyscy go rozpoznają. Ale wyobraź sobie futurew aplikacji finansowej. Czy jest to umowa kupna lub sprzedaży czegoś w określonym terminie? Nie, nie jest. Jeśli kod mówi std::future, że nie byłbyś tak łatwo zmieszany.
James Hollis,

2
@BrentRittenhouse może trochę zły przykład, istnieją co najmniej cztery różne biblioteki, które mają cout. Może być „czy to standardowa biblioteka? Libstdc ++? Stl? Coś innego?” I nie, nie każdy zna std :: cout, przynajmniej nieodłącznie, 6 z 7 nowych pracowników, których otrzymujemy, nie wie. Ponieważ programy nauczania nie wykorzystują tych w edukacji. Muszę przegonić printfs. Lub debugowania () - z Qt.
Swift - piątek Pie

1
Naprawdę? Jest to prawie w pierwszym przykładzie pierwszego rozdziału tak wielu książek o C ++, jeśli cokolwiek to (z użyciem operatora wstawiania) jest jedynym C ++, o którym wiedzą niektóre nowe bods.
mckenzm

@mckenzm Mógłbym umieścić to w książce lub notatkach z wykładów, aby zmniejszyć bałagan, ale nie w kodzie
Martin Beckett

45

Doświadczeni programiści używają wszystkiego, co rozwiązuje ich problemy i unikają tego, co stwarza nowe problemy, i unikają dyrektyw używania na poziomie plików nagłówkowych z tego właśnie powodu.

Doświadczeni programiści starają się również unikać pełnej kwalifikacji nazw w swoich plikach źródłowych. Niewielkim powodem jest to, że pisanie większej ilości kodu, gdy mniej kodu jest wystarczające, nie jest eleganckie, chyba że istnieją uzasadnione powody . Głównym tego powodem jest wyłączenie wyszukiwania zależnego od argumentów (ADL).

Jakie są te dobre powody ? Czasami programiści wyraźnie chcą wyłączyć ADL, innym razem chcą ujednoznacznić.

Więc następujące są w porządku:

  1. Dyrektywy i deklaracje użycia na poziomie funkcji wewnątrz implementacji funkcji
  2. Deklaracja użycia na poziomie pliku źródłowego w plikach źródłowych
  3. (Czasami) dyrektywy na poziomie pliku źródłowego

43

Zgadzam się, że nie powinien być używany globalnie, ale nie jest tak źle używać lokalnie, jak w namespace. Oto przykład z „The C ++ Programming Language” :

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

W tym przykładzie rozwiązaliśmy potencjalne konflikty nazw i niejednoznaczności wynikające z ich składu.

Nazwy wyraźnie tam zadeklarowane (w tym nazwy zadeklarowane przy użyciu deklaracji użycia, takich jak His_lib::String) mają pierwszeństwo przed nazwami udostępnionymi w innym zakresie za pomocą dyrektywy using ( using namespace Her_lib).


29

Uważam to również za złą praktykę. Dlaczego? Pewnego dnia pomyślałem, że funkcją przestrzeni nazw jest dzielenie rzeczy, więc nie powinienem zepsuć tego wrzucaniem wszystkiego do jednej globalnej torby.

Jeśli jednak często używam „cout” i „cin”, piszę: using std::cout; using std::cin;w pliku .cpp (nigdy w pliku nagłówkowym, jak się propaguje #include). Myślę, że nikt rozsądny nigdy nie nazwie strumienia coutani cin. ;)


7
To lokalna deklaracja użycia , coś zupełnie innego niż dyrektywa użycia .
sbi

25

Miło jest widzieć kod i wiedzieć, co robi. Jeśli widzę std::cout, wiem, że to coutstrumień stdbiblioteki. Jeśli widzę cout, to nie wiem. Może to być coutstrumień stdbiblioteki. Lub może być int cout = 0;dziesięć linii wyżej w tej samej funkcji. Lub staticzmienna nazwana coutw tym pliku. To może być cokolwiek.

Teraz weź milion kodów wiersza, który nie jest szczególnie duży, i szukasz błędu, co oznacza, że ​​wiesz, że jeden milion wierszy nie wykonuje tego, co powinien. cout << 1;mógł odczytać static intnazwany cout, przesunąć go w lewo o jeden bit i wyrzucić wynik. Szukając błędu, musiałbym to sprawdzić. Czy widzisz, jak naprawdę wolę widzieć std::cout?

Jest to jedna z tych rzeczy, które wydają się być naprawdę dobrym pomysłem, jeśli jesteś nauczycielem i nigdy nie musiałeś pisać i utrzymywać żadnego kodu do życia. Uwielbiam widzieć kod, w którym (1) wiem, co on robi; oraz (2) Jestem przekonany, że osoba, która to pisze, wiedziała, co robi.


4
Skąd wiesz, że „std :: cout << 1” nie odczytuje statycznego int nazwanego cout w przestrzeni nazw std, przesuwając go o jeden i wyrzucając wynik? A skąd wiesz, co robi „<<”;) ??? ... wydaje się, że ta odpowiedź nie jest dobrym punktem danych, aby uniknąć „używania”.
nyholku

4
Jeśli ktoś zmienił definicję std :: cout na liczbę całkowitą, oznacza to, że twój problem nie jest techniczny, ale społeczny - ktoś ma to dla ciebie. (i prawdopodobnie powinieneś również sprawdzić wszystkie nagłówki pod kątem #define true false, itp.)
Jeremy Friesner

2
Kiedy widzę cout, zawsze wiem, że to std :: cout. Jeśli się mylę, to problem osoby, która napisała ten kod, a nie mnie :)
Tien Do

22

Chodzi o zarządzanie złożonością. Korzystanie z przestrzeni nazw spowoduje wciągnięcie rzeczy, których nie chcesz, a tym samym może utrudnić debugowanie (mówię prawdopodobnie). Używanie std :: w dowolnym miejscu jest trudniejsze do odczytania (więcej tekstu i tak dalej).

Konie na kursy - zarządzaj swoją złożonością, jak najlepiej potrafisz i czujesz się w stanie.


18

Rozważać

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


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

class stringstream {  // Uh oh
};

Pamiętaj, że jest to prosty przykład. Jeśli masz pliki z 20 dołączeniami i innymi importami, będziesz mieć mnóstwo zależności, aby przejść do rozwiązania problemu. Najgorsze jest to, że w innych modułach można uzyskać niepowiązane błędy w zależności od sprzecznych definicji.

Nie jest to okropne, ale zaoszczędzisz sobie bólu głowy, nieużywając go w plikach nagłówków lub globalnej przestrzeni nazw. Prawdopodobnie dobrze jest to robić w bardzo ograniczonych zakresach, ale nigdy nie miałem problemu z wpisaniem dodatkowych pięciu znaków, aby wyjaśnić, skąd biorą się moje funkcje.


18
  1. Musisz umieć czytać kod napisany przez ludzi, którzy mają inny styl i opinie na temat najlepszych praktyk niż Ty.

  2. Jeśli tylko używasz cout, nikt się nie myli. Ale kiedy masz dużo przestrzeni nazw latających i widzisz tę klasę i nie jesteś do końca pewien, co ona robi, wyraźne określenie przestrzeni nazw działa jak komentarz. Na pierwszy rzut oka widać „och, to jest operacja systemu plików” lub „robi to w sieci”.


17

Używanie wielu przestrzeni nazw jednocześnie jest oczywiście receptą na katastrofę, ale używanie przestrzeni nazw JUST stdi tylko przestrzeni nazwstd nie jest moim zdaniem wielkim problemem, ponieważ redefinicja może nastąpić tylko na podstawie własnego kodu ...

Więc po prostu rozważ ich funkcje jako zastrzeżone nazwy, takie jak „int” lub „class” i to wszystko.

Ludzie powinni przestać być tak anonimowi. Twój nauczyciel miał rację przez cały czas. Wystarczy użyć JEDNEJ przestrzeni nazw; taki jest sens używania przestrzeni nazw na pierwszym miejscu. Nie należy używać więcej niż jednego jednocześnie. Chyba że to twoje. Ponownie, redefinicja nie nastąpi.


Tworzenie kolizji nie jest takie trudne - jak krótkie łańcuchy min , endi lesspojawiają się w std::przestrzeni nazw. Co więcej, teraz, gdy std::ma w sobie tysiące symboli, przydatne jest, aby czytelnik wiedział, skąd pochodzi nowy symbol, którego mogą nie znać.
Tom Swirly

Przestrzeń nazw std istnieje, ponieważ ludzie, zarówno ty, koledzy, jak i osoby piszące oprogramowanie pośrednie, których używasz, nie zawsze rozumieją umieszczanie funkcji w przestrzeniach nazw. W ten sposób możesz zaimportować wszystkie std :: i nic więcej, jednocześnie wywołując kolizję między, powiedzmy, std :: min a czyimś spuścizną :: min () sprzed czasu, gdy było w standardzie.
Aiken Drum

14

Zgadzam się z innymi tutaj, ale chciałbym zająć się obawami dotyczącymi czytelności - możesz tego wszystkiego uniknąć, po prostu używając typedefs na górze pliku, funkcji lub deklaracji klasy.

Zwykle używam go w mojej deklaracji klasy, ponieważ metody w klasie mają tendencję do radzenia sobie z podobnymi typami danych (członkami), a typedef to możliwość przypisania nazwy, która ma znaczenie w kontekście klasy. To faktycznie poprawia czytelność w definicjach metod klasowych.

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

oraz we wdrażaniu:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

w przeciwieństwie do:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

lub:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}

Tylko drobny komentarz, podczas gdy typedef jest przydatny, rozważyłbym utworzenie klasy reprezentującej linie zamiast używania typedef.
Eyal Solnik

14

Konkretny przykład wyjaśniający problem. Wyobraź sobie, że masz sytuację, w której masz dwie biblioteki fooi barkażda z własną przestrzenią nazw:

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

namespace bar {
    ...
}

Załóżmy teraz, że używasz fooi barrazem w swoim własnym programie w następujący sposób:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

W tym momencie wszystko jest w porządku. Po uruchomieniu programu „robi coś”. Ale później zaktualizujesz bari powiedzmy, że zmieniło się to tak:

namespace bar {
    void a(float) { /* Does something completely different */ }
}

W tym momencie pojawi się błąd kompilatora:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

Musisz więc wykonać pewne czynności konserwacyjne, aby wyjaśnić, że „a” oznacza foo::a. To niepożądane, ale na szczęście jest dość łatwe (wystarczy dodać foo::przed wszystkimi połączeniami za że kompilator oznaczy jako niejednoznaczny).

Ale wyobraź sobie alternatywny scenariusz, w którym zamiast tego pasek zmienia się i wygląda tak:

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

W tym momencie twoje wezwanie do a(42)nagle wiąże się bar::azamiast foo::ai zamiast robić „coś” robi „coś zupełnie innego”. Żadnych ostrzeżeń kompilatora ani nic takiego. Twój program po prostu po cichu zaczyna robić coś zupełnie innego niż wcześniej.

Korzystając z przestrzeni nazw, ryzykujesz taki scenariusz, dlatego ludzie nie czują się komfortowo, używając przestrzeni nazw. Im więcej rzeczy w przestrzeni nazw, tym większe ryzyko konfliktu, więc ludzie mogą być jeszcze bardziej niekomfortowi podczas korzystania z przestrzeni nazwstd (z powodu liczby rzeczy w tej przestrzeni nazw) niż w innych przestrzeniach nazw.

Ostatecznie jest to kompromis między zapisywalnością a niezawodnością / konserwowalnością. Czytelność może również uwzględniać, ale widziałem argumenty przemawiające w obu kierunkach. Zwykle powiedziałbym, że niezawodność i łatwość konserwacji są ważniejsze, ale w tym przypadku będziesz stale płacić koszty zapisu za dość rzadki wpływ na niezawodność / łatwość konserwacji. „Najlepszy” kompromis określi twój projekt i twoje priorytety.


Drugi scenariusz sprawdza mnie. Nie ma już przestrzeni nazw. Pod maską nie można wykryć tak subtelnych zmian w funkcjonalności.
safe_malloc

13

Przestrzeń nazw to nazwany zakres. Przestrzenie nazw służą do grupowania powiązanych deklaracji i oddzielania oddzielnych elementów. Na przykład dwie osobno opracowane biblioteki mogą używać tej samej nazwy w odniesieniu do różnych elementów, ale użytkownik może nadal używać obu:

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    // ...
}

namespace Yourlib{
    class Stack{ /* ... */ };
    // ...
}

void f(int max) {
    Mylib::Stack<int> s1(max); // Use my stack
    Yourlib::Stack    s2(max); // Use your stack
    // ...
}

Powtarzanie nazwy przestrzeni nazw może rozpraszać uwagę zarówno czytelników, jak i pisarzy. W związku z tym można stwierdzić, że nazwy z określonej przestrzeni nazw są dostępne bez wyraźnej kwalifikacji. Na przykład:

void f(int max) {
    using namespace Mylib; // Make names from Mylib accessible
    Stack<int> s1(max); // Use my stack
    Yourlib::Stack s2(max); // Use your stack
    // ...
}

Przestrzenie nazw stanowią potężne narzędzie do zarządzania różnymi bibliotekami i różnymi wersjami kodu. W szczególności oferują one programistom alternatywne sposoby wyraźnego odwołania się do nielokalnej nazwy.

Źródło: Przegląd języka programowania C ++ autorstwa Bjarne Stroustrup


4
Bardzo interesujące, że ta odpowiedź, która jest oparta na wskazówkach innych, że Bjarne Stroustrup zarobił -2 ... chłopiec Bjarne musiał być biednym i niedoświadczonym programistą, kiedy wprowadził tę funkcję do C ++
nyholku

@nyholku: Zobacz to .
sbi

10

Przykład, w którym using namespace stdzgłaszany jest błąd kompilacji z powodu niejednoznaczności zliczania, która jest również funkcją biblioteki algorytmów.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}

2
::count--problem rozwiązany. Zwykle będziesz mieć więcej rzeczy ze standardowej przestrzeni nazw niż z innych miejsc, więc utrzymywanie dyrektywy używającej przestrzeni nazw może zaoszczędzić ci pisania.
PSkocik,

Prawdziwy problem polega na tym, że C ++ wciąż ma globale bez przestrzeni nazw. To oraz fakt, że „to” jest ukryte w metodach, powoduje tyle błędów i problemów, że nie mogę ich nawet policzyć, nawet przy odpowiedniej zmiennej „count”. ;)
Aiken Drum

9

Nie pogarsza to wydajności oprogramowania ani projektu. Włączenie przestrzeni nazw na początku kodu źródłowego nie jest złe. Uwzględnienie using namespace stdinstrukcji różni się w zależności od potrzeb i sposobu opracowywania oprogramowania lub projektu.

namespace stdZawiera C ++ standardowe funkcje i zmienne. Ta przestrzeń nazw jest przydatna, gdy często używasz standardowych funkcji C ++.

Jak wspomniano na tej stronie :

Instrukcja używająca przestrzeni nazw std jest ogólnie uważana za złą praktykę. Alternatywą dla tej instrukcji jest określenie przestrzeni nazw, do której należy identyfikator, za pomocą operatora zasięgu (: :) za każdym razem, gdy deklarujemy typ.

I zobacz tę opinię :

Nie ma problemu z użyciem „using namespace std” w pliku źródłowym, gdy intensywnie korzystasz z przestrzeni nazw i wiesz na pewno, że nic nie koliduje.

Niektórzy mówili, że włączanie using namespace stdplików źródłowych do plików źródłowych jest złą praktyką, ponieważ wywołujesz z tej przestrzeni nazw wszystkie funkcje i zmienne. Gdy chcesz zdefiniować nową funkcję o tej samej nazwie co inna funkcja w niej zawarta namespace std, przeciążasz tę funkcję i może to powodować problemy z powodu kompilacji lub wykonania. Nie będzie się kompilować ani wykonywać zgodnie z oczekiwaniami.

Jak wspomniano na tej stronie :

Chociaż instrukcja oszczędza nam wpisywania std :: za każdym razem, gdy chcemy uzyskać dostęp do klasy lub typu zdefiniowanego w przestrzeni nazw std, importuje ona całą przestrzeń nazw std do bieżącej przestrzeni nazw programu. Weźmy kilka przykładów, aby zrozumieć, dlaczego może to nie być tak dobre

...

Teraz, na późniejszym etapie rozwoju, chcemy użyć innej wersji cout, która jest niestandardowo zaimplementowana w bibliotece o nazwie „foo” (na przykład)

...

Zauważ, że istnieje dwuznaczność, na którą bibliotekę wskazuje cout? Kompilator może to wykryć i nie skompilować programu. W najgorszym przypadku program może nadal się kompilować, ale wywołać niewłaściwą funkcję, ponieważ nigdy nie określono, do której przestrzeni nazw należy identyfikator.


8

Nie sądzę, aby była to zła praktyka we wszystkich warunkach, ale musisz zachować ostrożność, gdy z niej korzystasz. Jeśli piszesz bibliotekę, prawdopodobnie powinieneś użyć operatorów rozdzielczości zakresu z przestrzenią nazw, aby powstrzymać swoją bibliotekę przed wpadaniem na inne biblioteki. W przypadku kodu poziomu aplikacji nie widzę w nim nic złego.


7

„Dlaczego„ używa przestrzeni nazw std; ” uważałeś za złą praktykę w C ++? ”

Mówię inaczej: dlaczego wpisywanie pięciu dodatkowych znaków jest przez niektórych uważane za nieporęczne?

Rozważ np. Napisanie oprogramowania numerycznego. Dlaczego miałbym nawet brać pod uwagę zanieczyszczenie mojej globalnej przestrzeni nazw przez zmniejszenie ogólnego „std :: vector” do „vector”, gdy „vector” jest jedną z najważniejszych koncepcji domeny problemowej?


19
To nie tylko 5 dodatkowych znaków; 5 dodatkowych znaków za każdym razem, gdy odwołujesz się do dowolnego typu obiektu w standardowej bibliotece. Co, jeśli bardzo często korzystasz ze standardowej biblioteki, będzie często. Bardziej realistycznie są to tysiące dodatkowych znaków w przyzwoitym programie. Przypuszczalnie do języka dodano dyrektywę „za pomocą”, aby można ją było stosować ...
Jeremy Friesner,

5
Nie jest to 5 dodatkowych znaków za każdym razem, jest to 5 znaków i prawdopodobnie kilka kliknięć myszką, aby rozwinąć menu i wykonać Znajdź i zamień w wybranym edytorze.
DaveWalley,

1
Czytelność. cout << hex << setw(4) << i << endl;jest łatwiejszy do odczytania niżstd::cout << std::hex << std::setw(4) << i << std::endl;
oz1cz

16
Co gorsza: std::map<std::string,std::pair<std::string,std::string>>jest okropny w porównaniu do map<string,pair<string,string>>.
oz1cz

4
Dobrą praktyką jest pisanie na klawiaturze i tak kontenerów STL, więc std :: naprawdę nie ma znaczenia. A C ++ 11 przyniósł nam słowo kluczowe auto, które czyni wszystko jeszcze łatwiejszym, np. Przy użyciu iteratorów.
juzzlin

7

Zgadzam się z innymi - żąda konfliktów nazw, dwuznaczności, a faktem jest, że jest mniej wyraźny. Chociaż widzę użycie using, moim osobistym wyborem jest ograniczenie go. Chciałbym również mocno rozważyć to, co zauważyli inni:

Jeśli chcesz znaleźć nazwę funkcji, która może być dość popularną nazwą, ale chcesz ją znaleźć tylko w stdprzestrzeni nazw (lub odwrotnie - chcesz zmienić wszystkie wywołania, które nie znajdują się w przestrzeni nazw std, przestrzeni nazw X, ...), to jak proponujesz to zrobić?

Możesz napisać program, aby to zrobić, ale czy nie lepiej byłoby poświęcić czas na pracę nad samym projektem, niż na pisanie programu do obsługi projektu?

Osobiście nie mam nic przeciwko temu std::prefiksowi. Lubię ten wygląd bardziej niż brak go. Nie wiem, czy to dlatego, że jest jawne i mówi mi „to nie jest mój kod ... używam standardowej biblioteki”, czy jest to coś innego, ale myślę, że wygląda to ładniej. To może być dziwne, biorąc pod uwagę, że dopiero niedawno dostałem się do C ++ (używałem i nadal gram w C i innych językach znacznie dłużej, a C jest moim ulubionym językiem wszechczasów, zaraz po asemblerze).

Jest jeszcze jedna rzecz, chociaż jest ona nieco związana z powyższym i tym, na co wskazują inni. Chociaż może to być złą praktyką, czasami rezerwuję std::namestandardową wersję biblioteki i nazwę dla implementacji specyficznej dla programu. Tak, może to cię ugryźć i mocno ugryźć, ale wszystko sprowadza się do tego, że rozpocząłem ten projekt od zera i jestem jedynym programistą. Przykład: przeciążam std::stringi nazywam to string. Mam pomocne dodatki. Zrobiłem to częściowo z powodu mojej skłonności do C i Unixa (+ Linux) do małych liter.

Poza tym możesz mieć aliasy przestrzeni nazw. Oto przykład przydatnego zastosowania, do którego nie można było się odwoływać. Korzystam ze standardu C ++ 11, a konkretnie z libstdc ++. Cóż, nie ma pełnego std::regexwsparcia. Jasne, kompiluje się, ale zgłasza wyjątek w postaci błędu po stronie programisty. Ale to brak wdrożenia.

Oto jak to rozwiązałem. Zainstaluj regex Boosta i połącz go. Następnie wykonuję następujące czynności, aby po całkowitym wdrożeniu libstdc ++ potrzebowałem tylko usunąć ten blok, a kod pozostanie taki sam:

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

Nie będę się kłócił, czy to zły pomysł, czy nie. Będę jednak argumentować, że utrzymuje go w czystości dla mojego projektu, a jednocześnie czyni go konkretnym: To prawda, muszę użyć Boosta, ale używam go tak, jakby libstdc ++ go w końcu miał. Tak, rozpoczęcie własnego projektu i rozpoczęcie od standardowego (...) na samym początku bardzo pomaga w utrzymaniu, rozwoju i we wszystkim, co jest związane z projektem!

Żeby coś wyjaśnić: nie sądzę, że dobrym pomysłem jest używanie nazwy klasy / czegokolwiek w STL celowo i bardziej konkretnie zamiast. Ciąg jest dla mnie wyjątkiem (zignoruj ​​pierwszy, powyżej lub drugi tutaj, pun, jeśli musisz) dla mnie, ponieważ nie podobał mi się pomysł „String”.

W tej chwili jestem nadal bardzo stronniczy w stosunku do C i stronniczy w stosunku do C ++. Oszczędzanie szczegółów, większość tego, nad czym pracuję, bardziej pasuje do C (ale było to dobre ćwiczenie i dobry sposób, aby a. Nauczyć się innego języka i b. Starać się nie być mniej stronniczy w stosunku do obiektów / klas / itp., Co może lepiej powiedzieć jako mniej zamknięte, mniej aroganckie i bardziej akceptujące). Ale to, co jest użyteczne, co niektórzy już zaproponował: I rzeczywiście używają listy (jest dość ogólny, prawda?), A sort (samo), aby wymienić tylko dwa, które spowodowałyby nazwę starcia gdybym miał zrobić using namespace std;, i tak w tym celu wolę być konkretny, kontrolować i wiedząc, że jeśli zamierzam być standardowym zastosowaniem, będę musiał to określić. Mówiąc wprost: żadne założenie nie jest dozwolone.

A jeśli chodzi o włączenie wyrażenia regularnego Boost std. Robię to w celu przyszłej integracji i - ponownie, w pełni przyznam, że to stronniczość - nie sądzę, aby było tak brzydkie jak boost::regex:: .... Rzeczywiście, to dla mnie kolejna rzecz. W C ++ jest wiele rzeczy, które muszę jeszcze zaakceptować w wyglądzie i metodach (inny przykład: szablony variadic kontra var argumenty [choć przyznaję, że szablony variadic są bardzo przydatne!]). Nawet te, które akceptuję, były trudne i nadal mam z nimi problemy.


1
Rozszerzenie stdprzestrzeni nazw jest zachowaniem niezdefiniowanym i dlatego nigdy nie powinno się tego robić.
tambre

7

Z moich doświadczeń wynika, że ​​jeśli masz wiele bibliotek, które używają powiedz cout, ale w innym celu możesz użyć złego cout.

Na przykład, jeśli wpisam, using namespace std; a using namespace otherlib;i wpisz po prostu cout(co dzieje się w obu), zamiast std::cout(lub 'otherlib::cout'), możesz użyć złego, i pojawiają się błędy. Jest o wiele bardziej skuteczny i wydajny w użyciu std::cout.


6

W przypadku niekwalifikowanych importowanych identyfikatorów potrzebujesz zewnętrznych narzędzi wyszukiwania, takich jak grep, aby dowiedzieć się, gdzie identyfikowane są identyfikatory. Utrudnia to rozumowanie na temat poprawności programu.


6

To zależy od tego, gdzie się znajduje. Jeśli jest to wspólny nagłówek, to zmniejszasz wartość przestrzeni nazw, scalając ją z globalną przestrzenią nazw. Pamiętaj, że może to być fajny sposób na tworzenie globałów modułowych.


6

Jest to zła praktyka, często znana jako globalne zanieczyszczenie przestrzeni nazw. Problemy mogą wystąpić, gdy więcej niż jedna przestrzeń nazw ma tę samą nazwę funkcji z podpisem, wówczas kompilator nie będzie mógł zdecydować, który z nich wywołać, a tego wszystkiego można uniknąć, określając przestrzeń nazw za pomocą wywołania funkcji std::cout. Mam nadzieję że to pomoże. :)


5

Aby odpowiedzieć na twoje pytanie, patrzę na to w ten sposób praktycznie: wielu programistów (nie wszyscy) wywołuje przestrzeń nazw std. Dlatego należy przyzwyczaić się NIE używać rzeczy, które wpływają lub używają tych samych nazw, co w std przestrzeni nazw. To wielka sprawa, ale nie tyle w porównaniu z liczbą możliwych spójnych słów i pseudonimów, które można wymyślić ściśle.

Mam na myśli naprawdę ... powiedzenie „nie polegaj na tym, że jesteś obecny” oznacza po prostu ustawienie się na poleganie na tym, że NIE jest obecny. Ciągle będziesz mieć problemy z pożyczaniem fragmentów kodu i ciągłą ich naprawą. Po prostu trzymaj swoje zdefiniowane przez użytkownika i pożyczone rzeczy w ograniczonym zakresie, tak jak powinny, i BARDZO oszczędzaj z globalsami (szczerze mówiąc, globals prawie zawsze powinny być ostatecznością w celu „skompiluj teraz, rozsądek później”). Naprawdę myślę, że to zła rada od twojego nauczyciela, ponieważ użycie std będzie działać zarówno dla „cout”, jak i „std :: cout”, ale NIE użycie std będzie działać tylko dla „std :: cout”. Nie zawsze będziesz miał szczęście, aby napisać cały swój kod.

UWAGA: Nie skupiaj się zbytnio na problemach z wydajnością, dopóki nie dowiesz się trochę o tym, jak działają kompilatory. Przy odrobinie doświadczenia w kodowaniu nie musisz się dużo o nich uczyć, zanim zdasz sobie sprawę, ile potrafią uogólnić dobry kod w coś prostego. Wszystko jest tak proste, jakbyś napisał całość w C. Dobry kod jest tak skomplikowany, jak powinien.


Biorąc pod uwagę, jak wielu ludzi nie zdaje sobie sprawy z użytecznych standardowych funkcji bibliotecznych ( <algorithm>na przykład wymyślając na nowo rzeczy ), wydaje się nieco trudniej wyobrazić sobie, że ci sami ludzie mogliby niezawodnie unikać tych identyfikatorów. Przejrzyj własny kod i powiedz mi, że nigdy nie masz wywołanej zmiennej lub funkcji count. Albo distance, albo log, destroy, launch, visit, beta, sample, messages, clamp, erase, copy, modulus, left, itd. Nie wspominając wszystkie identyfikatory nie są jeszcze w stdktóry złamie kod C ++ 35, gdy wychodzi ...
Toby Speight
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.