Używać `using` w C ++, czy go unikać?


17

Pomijanie subtelnie odmiennej semantyki z powodu ADL, jak ogólnie powinienem używać usingi dlaczego? Czy to zależy od sytuacji (np. Nagłówek, który będzie #included kontra plik źródłowy, który nie będzie)?

Należy również podkreślić, wolę ::std::albo std::?

  1. Poziom przestrzeni nazw using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Będąc w pełni jawnym:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Deklaracje użycia na poziomie przestrzeni nazw:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. Lokalne funkcje-deklaracje użycia:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Funkcja lokalna using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Coś innego?

Zakłada się, że jest to wersja wcześniejsza niż C ++ 14, a zatem nie stosuje się dedukcji typu zwrotu auto.



@AProgrammer: Ach, dziękuję za link, który odpowiada na część mojego pytania. :) Wciąż zastanawiasz ::std::vs. std::chociaż.
user541686,

4
Używam jednak stdbez sekundy. Ktoś definiujący przestrzeń nazw std prosi o kłopoty (i prawdopodobnie stara się skorzystać, że większość ludzi używa, stda nie używa ::std).
AProgrammer

Odpowiedzi:


25

Unikaj używania usingw nagłówkach, ponieważ narusza to cel przestrzeni nazw.

Można go używać w plikach źródłowych, ale w niektórych przypadkach nadal go unikałbym (na przykład using std).

Jeśli jednak masz zagnieżdżone przestrzenie nazw, jest w porządku:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A

6
+1 to zadziwiające, jak wiele samouczków i kursów uniwersyteckich mówi ci, żebyś używał usingsłowa kluczowego bez dokładnego wyjaśnienia, dlaczego na początku używa się przestrzeni nazw.
Jeffrey Sweeney

Ludzie chcą korzystać z iostreams, ciągów znaków i tak dalej. Nie chcą wpisywać std :: za każdym razem, gdy chcą czegoś użyć, lub muszą pamiętać o innym kafelku, który należy umieścić przed kodem, co spowoduje niezbyt pomocne błędy, jeśli o tym zapomną . :(
Colen

Czy coś takiego jak typedef std :: string sstring; być alternatywą?
Giorgio

1
@ Colen: Te biedne dusze mogą używać using std::couti przyjaciele, ale to już nie tak coutstrasznie długie imię.
Benjamin Bannier

1
Jeśli jesteś studentem pierwszego dnia „mojej pierwszej klasy języka C ++”, jest to kolejna rzecz, która może powodować błędy składniowe, których nie rozumiesz. Łatwo jest nam to rozgryźć, ponieważ jesteśmy doświadczonymi programistami, ale kiedy próbujesz nauczyć się języka, musisz martwić się, że nie potrzebujesz.
Colen,

11

Umieszczając instrukcję using w pliku źródłowym, PROSZĘ, po prostu ściągnij to, czego potrzebujesz. Na przykład:

using std::string;
using std::ostringstream;

Problem polega na tym, że jeśli to zrobisz

using namespace std;

wciągasz KAŻDĄ POJEDYNCZĄ RZECZ ze standardowego obszaru nazw do globalnej przestrzeni nazw. Co prowadzi do bardzo interesujących komunikatów o błędach, gdy przypadkowo użyjesz w kodzie nazwy, która odpowiada tej, o której nie wiedziałeś w standardzie. Jeśli po prostu wciągniesz to, co chcesz, nie będziesz miał tego problemu (a ściślej mówiąc, następny programista, który będzie pracował nad twoim kodem, nie będzie miał tego problemu).


Alternatywnie możesz using namespacepo prostu w zakresie funkcji, unikając problemu.
Tamás Szelei

2
@fish - właściwie „używanie przestrzeni nazw” w zakresie funkcji nie pozwala uniknąć problemu, ogranicza po prostu przestrzeń, w której może się nie udać. A jeśli wstawisz „używanie przestrzeni nazw” w każdej funkcji, to niewiele różni się od robienia tego globalnie.
Michael Kohne,

Podczas gdy C ++ rzeczywiście pozwala deklarować typy na poziomie funkcji, nie jest to powszechne; poza tym możliwe konflikty nazw są łatwe do wykrycia z danych wyjściowych kompilatora (ale masz rację, że to nie zapobiegnie).
Tamás Szelei,

2

Jak wskazuje VJovic, nie należy używać usingw pliku nagłówkowym. usingw pliku nagłówkowym wpływa na bieżącą jednostkę kompilacji (plik .cpp) w sposób, którego plik źródłowy może nie oczekiwać.

using namespacenależy również unikać w pliku źródłowym. To przenosi każdy symbol do tego samego zakresu co plik źródłowy. Bardziej jasne dla czytelników jest to, co robisz, jeśli używasz określonych symboli z przestrzeni nazw.


2
Z praktycznego punktu widzenia, o ile Twój kod nie zastąpi powszechnie używanych nazw, wolałbym raczej zobaczyć using namespace JoystickModulena początku pliku .cpp niż JoystickModule::dołączyć do każdego obiektu.
Alex P

@AlexP: Właśnie tak to robię. Jedna usinginstrukcja dla mojej własnej przestrzeni nazw, nad którą obecnie pracuję, a wszystko inne pozostaje w przestrzeni nazw.
Benjamin Kloster,

Powinienem rozwinąć temat „używaj określonych symboli z przestrzeni nazw”. Zamiast prefiksu każdego symbolu przy każdym użyciu, co nie pomaga w czytelności, wolę używać jawnego podnoszenia symboli. using SomeNameSpace::SomeSymbol. Pozwala to uniknąć przenoszenia każdego symbolu z przestrzeni nazw do bieżącego zakresu.
Bill Door

0

Pisanie usingw Nagłówkach to najlepszy sposób na tworzenie wszelkiego rodzaju nieprzyjemnych i niemożliwych do debugowania błędów. Czy nie to zrobić.

Pisanie using namespace XYZw pliku źródłowym jest trochę lepsze, ale wciąż może powodować niezliczone bóle głowy. Bezpiecznym sposobem jest wyraźne określenie, czego używasz, np using Foo::Bar.

Załóżmy, że masz plik Bar.cpp z następującymi elementami:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

Funkcja działała dobrze, aż pewnego dnia - pozornie bez żadnych zmian kodu w odpowiednich klasach - jej zachowanie się zmieniło: nagle nagle currentIndexwydaje się, że jest wyłączony o jeden . Przeglądając ostatnie zmiany nie odkryjesz żadnych zmian, nawet zdalnie związanych z kodem.

W końcu odkrywasz przyczynę:
Ty (pośrednio) jesteś Foo.hgdzieś. W plikach przestrzeni nazw Foo dodano nową funkcję:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Który jest zdecydowanie lepszy increment(int)niż twoja funkcja increment(double)- więc teraz Foo::increment()funkcja jest wywoływana przez Bar::someFunction(). Ups

(A gdybyś napisał usingw Nagłówkach, które using namespace Foorównie dobrze mogą znajdować się w dowolnym miejscu twojego drzewa dołączeń ...)

Więc ... Nie pisz żadnych usingw Nagłówkach, a także uważaj na pisanie using namespacew plikach źródłowych.

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.