Korzystanie ze standardowej przestrzeni nazw

110

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?

paoloricardo
źródło

Odpowiedzi:

131

Większość użytkowników C ++ jest całkiem zadowolona z czytania std::string, std::vectoritp. W rzeczywistości, widok surowego pliku vectorsprawia, że ​​zastanawiam się, czy to jest std::vectorzdefiniowany przez użytkownika, czy inny vector.

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 stdprzestrzeni nazw: count, sort, find, equal, reverse. Posiadanie zmiennej lokalnej o nazwie countoznacza, że using namespace stdnie będzie można jej użyć countzamiast std::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.

#include <algorithm>
using namespace std;

int count = 0;

int increment()
{
    return ++count; // error, identifier count is ambiguous
}

Błąd jest zwykle długi i nieprzyjazny, ponieważ std::countjest to szablon z kilkoma długimi zagnieżdżonymi typami.

Jest to jednak w porządku, ponieważ std::countprzechodzi do globalnej przestrzeni nazw, a funkcja count ją ukrywa.

#include <algorithm>
using namespace std;

int increment()
{
    static int count = 0;
    return ++count;
}

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::countjest widoczny jak countw globalnej przestrzeni nazw, ale tylko wewnątrz increment.

#include <algorithm>

int increment()
{
    using namespace std;
    static int count = 0;
    return ++count;
}

I z podobnych powodów countjest tutaj niejednoznaczny. using namespace stdnie powoduje std::count, ukryj zewnętrzną, countjak można się spodziewać. Te using namespaceśrodki zasada, że std::countwygląd (w incrementfunkcji) tak, jakby to była zadeklarowana w zakresie globalnym, czyli w tym samym zakresie, jak int count = 0;i tym samym powoduje niejasności.

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}
CB Bailey
źródło
21
Ale to typy baaaardzo dużo łatwiejsze bez std :: prefiks!
xtofl
69
@xtofl: Nie, tak nie jest. Pięć znaków nie jest tak istotne podczas pisania, ale te pięć znaków może być bardzo istotne podczas czytania. Łatwość czytania liczy się znacznie bardziej niż łatwość pisania kodu źródłowego, ponieważ kod jest znacznie bardziej czytany niż pisany.
sbi
3
Możesz dodać, że instrukcja using zachowuje się poprawnie z regułami zakresu.
Martin York
2
@Martin York: zaktualizowano o przykłady ilustrujące zasady określania zakresu. @Michael Burr: Prawdopodobnie nie jest tak źle, naprawdę nie podoba mi się to, że komunikaty o błędach dotyczące prostych błędów są dużo trudniejsze do zinterpretowania lub w ogóle się nie zdarzają. Na przykład, jeśli uważa się, że funkcja znajduje się w zakresie, ale nie jest, a std :: function jest, zamiast otrzymać pomocny błąd „identyfikator nierozpoznany”, często kończy się to z bardziej niejasnym ”argumentem nie można przekonwertować X ”lub„ nie można wygenerować funkcji na podstawie szablonu ”błąd stylu. Gorzej jest, gdy po cichu wywoływana jest niewłaściwa funkcja. To rzadkie, ale się zdarza.
CB Bailey,
5
Cóż, jestem zaskoczony, że nikt nie rozmawiał o opcji using std::xxx;. Nie zanieczyszcza przestrzeni nazw, pisanie kodu będzie krótsze i myślę, że copyjest o wiele bardziej czytelne niż std::copy.
legends2k
41

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ć

using namespace std

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

using std::swap

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).

Yacoby
źródło
10
+1 za wzmiankę using std::swap(co jest jedyną rzeczą, której kiedykolwiek używam).
sbi
1
+1 za wzmiankę, która u n smoż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.
quamrana
1
Ale jeśli są zdefiniowaniu swaplub move(lub hash, lessitd.), Specjalizację, powinno być wprowadzenie tej specjalizacji w namespace stdkaż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&)};
AJMansfield
28

Najpierw trochę terminologii:

  • deklaracja użycia : using std::vector;
  • using-dyrektywa : 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

using namespace std;

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 jednak stdw 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 stdprzestrzeni 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):

template< typename T >
void foo( T& x, T& y)
{
    using std::swap;     // makes std::swap available in this function

    // do stuff...

    swap( x, y);         // will use a T-specific swap() if it exists,
                         //  otherwise will use std::swap<T>()

    // ...
 }

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:

W skrócie: możesz i powinieneś używać przestrzeni nazw, swobodnie używając deklaracji i dyrektyw w swoich plikach implementacji po #includedyrektywach i dobrze się z tym czujesz. Pomimo wielokrotnych twierdzeń, że jest inaczej, przestrzenie nazw używające deklaracji i dyrektyw nie są złe i nie są sprzeczne z celem przestrzeni nazw. To raczej one sprawiają, że przestrzenie nazw są użyteczne.

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:

Użyciu deklaracja dodaje nazwę do zakresu lokalnego. Użyciu Dyrektywa nie robi; po prostu udostępnia nazwy w zakresie, w którym zostały zadeklarowane. Na przykład:

namespaceX {
    int i , j , k ;
}

int k ;
void f1()
{
    int i = 0 ;

    using namespaceX ; // make names from X accessible

    i++; // local i
    j++; // X::j
    k++; // error: X::k or global k ?

    ::k ++; // the global k

    X::k ++; // X’s k
}

void f2()
{
    int i = 0 ;

    using X::i ; // error: i declared twice in f2()
    using X::j ;
    using X::k ; // hides global k

    i++;
    j++; // X::j
    k++; // X::k
}

Nazwa zadeklarowana lokalnie (zadeklarowana przez zwykłą deklarację lub przez deklarację using) ukrywa nielokalne deklaracje o tej samej nazwie, a wszelkie niedozwolone przeciążenia nazwy są wykrywane w miejscu deklaracji.

Zwróć uwagę na błąd niejednoznaczności k++w f1(). Nazwy globalne nie mają pierwszeństwa przed nazwami z przestrzeni nazw udostępnionych w zasięgu globalnym. Zapewnia to znaczną ochronę przed przypadkowymi konfliktami nazw i - co ważne - zapewnia, że ​​zanieczyszczenie globalnej przestrzeni nazw nie przynosi żadnych korzyści.

Gdy biblioteki deklarujące wiele nazw są udostępniane za pomocą dyrektyw using, istotną zaletą jest to, że kolizje nieużywanych nazw nie są uważane za błędy.

...

Mam nadzieję, że w porównaniu z tradycyjnymi programami w językach C i C ++, w nowych programach korzystających z przestrzeni nazw nastąpi radykalny spadek użycia nazw globalnych. Reguły dla przestrzeni nazw zostały specjalnie opracowane, aby nie dawać „leniwemu” użytkownikowi nazw globalnych żadnej przewagi nad kimś, kto dba o to, aby nie zanieczyszczać zasięgu globalnego.

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 stdprzestrzeni 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.

Michael Burr
źródło
Wracając do ostatniego punktu: Java i C # również mają znacznie ładniejsze przestrzenie nazw. Gdyby wszystko w BCL mieszkało w Systemie, „używanie Systemu” powodowałoby tyle samo problemów, co „używanie standardowej przestrzeni nazw”.
Jeff Hardy,
Ale programy Java i C #, które widzę, zazwyczaj zawierają wszystkie używane przez nie przestrzenie nazw - a nie tylko „System” (lub jego odpowiednik). Więc zamiast jednej dyrektywy using zawierającej wszystkie użyte nazwy, istnieje 5 lub 10, które robią mniej więcej to samo. Czy też "using namespace std;" naprawdę sprawia tyle kłopotów?
Michael Burr
Problem polega na tym, że std ma zbyt wiele popularnych nazw, a dołączenie jednego standardowego nagłówka może obejmować wszystkie inne. Nie mamy dobrej kontroli nad tym, co jest importowane, istnieje zbyt wiele zagrożeń. Nie wiem wystarczająco dużo o Javie i C #, ale znam Adę, która ma znacznie lepszy system modułów niż C ++ i gdzie importowanie nazw jest zwykle źle widziane. Ogólnie rzecz biorąc, najpierw jest to kwestia konwencji nazewnictwa (widziałem ludzi używających przedrostków, a także przestrzeni nazw, a nie importowanie nie ma sensu), a potem stylu.
AProgrammer
1
Nadal nie jestem przekonany, że to prawdziwy problem. Widzę, że dyrektywy using są używane cały czas bez poważnych wad. Z drugiej strony nie mam problemu z ich nie korzystaniem. Wolę tylko, aby std::kwalifikatory nie zaśmiecały kodu - są inne sposoby, aby tego uniknąć (użycie-deklaracji lub typedefs zwykle załatwia sprawę).
Michael Burr
1
@AProgrammer: mówisz, „lista jest naturalnym identyfikatorem listy identyfikacyjnej w interprecie lisp” - ale posiadanie using namespace std;dyrektywy „ ” nie przeszkadza w zadeklarowaniu swojego naturalnego identyfikatora list”- po prostu jeśli to zrobisz, nie możesz nie dłuższe użytkowanie std::listbez kwalifikacji. Nie różni się to od tego, " using namespace std;" jeśli nie ma dyrektywy. A może coś mi brakuje?
Michael Burr
17

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 Xnastępnie jest prawie bez ryzyka, a nie wykonanie tego prowadzi do głupiego wyglądu kodu PrefixNS::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

typedef struct list {} list;

Musieliśmy zintegrować i zaadaptować kod (który nadam nazwę „silnik”), który wyglądał następująco:

#include <list>
...
using std::list;
...
void foo(list const&) {}

Więc zmodyfikowaliśmy w ten sposób:

#include <list>

#include "module.h"
...
using std::list;
...
void foo(list const&) {}

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.

AProgrammer
źródło
1
Jednym z kontrolowanych przypadków, w których myślę, że użycie przestrzeni nazw jest dopuszczalne, jest publikowanie kodu. Uproszczenie ułatwia układ strony i pomaga skoncentrować się na eksponowanym punkcie. Wadą jest to, że tak naprawdę nie pokazuje dobrych praktyk, więc nie użyłbym go w książkach dla początkujących.
AProgrammer
1
Myślę wpisując std :: to mała cena za klarowność
paoloricardo
4
@paoloricardo: Z drugiej strony myślę, że std :: pojawiające się w każdym miejscu to niepotrzebny wizualny bałagan.
Michael Burr
1
@Michael: płacisz pieniądze i dokonujesz wyboru!
paoloricardo
2
Dziękujemy za poświęcenie czasu na opisanie szczegółów napotkanego problemu.
Michael Burr
4

Jeśli nie masz ryzyka konfliktów nazw w swoim kodzie z bibliotekami standardowymi i innymi, możesz użyć:

using namespace std;

Ale jeśli chcesz dokładnie poznać zależność twojego kodu od dokumentacji lub istnieje ryzyko konfliktu nazw, użyj innego sposobu:

using std::string;
using std::cout;

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 ...

Matthieu
źródło
4

Obie

using std::string;

i

using namespace std;

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.

Tadeusz Kopeć
źródło
3

Dla mnie wolę używać, ::gdy to możliwe.

std::list<int> iList;

Nienawidzę pisać:

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
    //
}

Mam nadzieję, że w C ++ 0x napisałbym to:

for(auto i = iList.begin(); i != iList.end(); i++)
{
    //
}

Jeśli przestrzeń nazw jest bardzo długa,

namespace dir = boost::filesystem;

dir::directory_iterator file("e:/boost");
dir::directory_iterator end;

for( ; file != end; file++)
{
    if(dir::is_directory(*file))
        std::cout << *file << std::endl;
}
AraK
źródło
@AraK: katalog przestrzeni nazw = boost :: filesystem; Myślę, że to alias?
paoloricardo
@paoloricardo: Tak, to jest to.
sbi
2
Iteratory powinny być inkrementowane za pomocą ++i, a nie i++dlatego, że jeśli jest nawet zdefiniowane, tworzy niepotrzebną tymczasową kopię iteratora.
Felix Dombek,
2

Nigdy nie powinieneś znajdować się using namespace stdw zakresie przestrzeni nazw w nagłówku. Przypuszczam też, że większość programistów będzie się zastanawiać, kiedy zobaczą vectorlub stringbez std::, więc myślę, że nie using namespace stdjest lepiej. Dlatego twierdzę, że nigdy nie będzie using 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, usingzwykle 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::swapco jest konieczne (szczególnie w kodzie ogólnym), aby odebrać przeciążenia swap(), których nie można umieścić w stdprzestrzeni nazw (ponieważ nie możemy umieszczać przeciążeń stdfunkcji w tej przestrzeni nazw).

sbi
źródło
3
Specjalizacja std :: swap byłaby całkowitą specjalizacją - nie można częściowo specjalizować się w szablonach funkcji. Każdy program jest wolno częściowo specjalizują żadnego Standard Template Library tak długo, jak to specjalizacja zależy od typu zdefiniowanego przez użytkownika.
CB Bailey,
@Charles: Tak, masz rację, oczywiście, nie ma FTPS. Mogę specjalizować się w szablonach std, ale nie przeciążam ich. Przepraszam za to bzdury. Poprawię post.
sbi
2
Nie sądzę, że intencją using namespacedyrektywy 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 mniej std::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.
Lumi,
1
@sbi: Nie, to nie jest obiektywne. Zależy to od tego, czy uważasz, że std :: jest pomocne, czy też nie jest bałaganem. Więcej bałaganu -> mniej klarowności.
Joshua Richardson
2

Przestrzenie nazw zawierają kod, aby zapobiec pomyłkom i zanieczyszczeniu sygnatur funkcji.

Oto kompletne i udokumentowane demo prawidłowego wykorzystania przestrzeni nazw :

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see /programming/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

Wynik:

Our log: 42
Standard log: 1.43508
Cees Timmerman
źródło
1

using namespace stdimportuje zawartość stdprzestrzeni 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ć, stdzapobiega 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 namespacew 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.

Wookai
źródło
2
using namespace std;importuje zawartość stdprzestrzeni nazw do globalnej przestrzeni nazw. Nie zmienia domyślnej przestrzeni nazw. Zdefiniowanie czegoś w globalnej przestrzeni nazw po a using namespace stdnie w magiczny sposób umieści to w stdprzestrzeni nazw.
CB Bailey
Przepraszam, nie to miałem na myśli. Dziękuję za zwrócenie uwagi, poprawię swoją odpowiedź.
Wookai,
1
Chłopaki: dzięki za odpowiedzi. Wydaje się, że generalnie bezpieczniej jest nie używać opcji „using namespace std” i unikać tworzenia potencjalnych niejasności. Podsumowując, użycie „std :: xxx” przemawia do mnie bardziej niż deklarowanie listy różnych funkcji na początku pliku źródłowego, ponieważ jednoznacznie określa, jakie są intencje.
paoloricardo
1
Cytat (z wyjątkiem sytuacji, gdy przestrzeń nazw jest zbyt długa). Możesz użyć aliasingu przestrzeni nazw, aby w tym pomóc. 'namespace Rv1 = Thor :: XML :: XPath :: Rules :: Light :: Version1;' Zwróć uwagę na aliasy i przestrzegaj obu zasad zakresu;
Martin York
0

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 stdna 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 albo using namespace std(jeśli używasz różnych klas), albo pojedynczych usings (używając kilku zajęcia często).

Sam Brightman
źródło
0

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„i while” 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.

xtofl
źródło
0

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 stdużywają.


źródło
-1

Jakie są zalety i wady każdego z nich

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.

Martin Beckett
źródło
Przestrzenie nazw nie są tak naprawdę zaprojektowane, aby umożliwić zastępowanie nazw różnymi, ale równoważnymi funkcjami. Mają na celu zapobieganie niezamierzonym konfliktom nazw.
Michael Burr
Tak, więc jedynym uzasadnieniem dla dyrektywy „using”, która to łamie, jest umożliwienie przełączenia funkcji do nowej przestrzeni nazw.
Martin Beckett
Myślę, że można znaleźć bardzo wielu programistów narzekających na ból przestrzeni nazw w dupie i chcących wyrzucić je przez okno, gdyby nie było dyrektywy using. O ile mi wiadomo, każdy język, który używa przestrzeni nazw, ma coś podobnego do dyrektywy using, która usuwa je z drogi, gdy chcesz, aby były z drogi. Jeśli dyrektywy są bezużyteczne, dlaczego istnieją wszędzie?
Michael Burr,
Myślę, że „używanie” miało na celu umożliwienie przełączenia się na alternatywne implementacje zamiast oszczędzania pisania 3 liter. Lubię używać "std :: Foo", ponieważ służy jako kontrakt dla programisty, że używam normalnego Foo i nie muszą sprawdzać. Zgadzam się, że nie chciałbym wpisywać „com.microsoft.visual-studio.standard-library.numbers.int foo”, niektóre deklaracje iteratorów w STL wyglądają tak. Python wykonuje niezłą robotę, pozwalając ci pobierać zdobione lub niezdekorowane zestawy funkcji z modułów.
Martin Beckett
-1

Dlaczego nie na przykład

typedef std::vector<int> ints_t;
ints_t ints1;
....
ints_t ints2;

zamiast nieporęcznego

std::vector<int> ints1;
...
std::vector<int> ints2;

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

void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);

które z nich zwracają wartość?

A może zamiast tego

typedef std::vector<unsigned int> values_t;
typedef std::vector<unsigned int> histogram_t;
...
void getHistogram(values_t&, histogram_t&); 
pies
źródło