2013-01-03 13 views
6

Zastanawiam się trochę o namespace i using w C++ zasadniczo chciałbym poznać różnice i dowiedzieć się, jak z niego korzystać w najlepszy sposób.C++ Rozdzielczość Nazwa

Jak widzę to istnieje (co najmniej) trzy sposoby rozwiązania nazwę klasy i nie jestem pewien, jak wybrać spośród nich:

  1. using namespace <namespace>
  2. using <namespace>::<what_to_use>
  3. <namespace>::<what_to_use> <use_it>

Chciałbym poznać zalety, szczególnie jeśli w grę wchodzi jeden utwór, jeśli jest to po prostu syntaktyczny i jestem pierwszeństwo lub jeśli są inne rzeczy, których nie rozważałem w związku z tym.

+1

Nie jest to związane z wydajnością środowiska wykonawczego. –

+1

Powiedziano mi, gdy byłem na studiach, że oprócz posiadania przestrzeni nazw w zakresie, używanie 'using namespace std;' również było pułapką bezpieczeństwa. –

+1

1. Odradza się z powodów, które opisujesz 2. Pomaga w korzystaniu z funkcji udostępnianych przez innych w ich własnych przestrzeniach nazw przy pomocy ADL (patrz 'std :: swap', ale niech odpowiedź lepiej ci to wytłumaczy) 3. Wolę większość, ale to kwestia gustu i może być uciążliwa, jeśli nie lubisz oglądać "std ::" wszędzie, jak ja. Ale żadna z nich nie ma różnic w wydajności, chodzi tylko o rozpoznawanie nazw i nie "" wkomponowuje się w rzeczywisty kod "*. –

Odpowiedz

5

Pierwszy jest using namespace directive, przynosi wszystkie nazwy symbolu z określonej przestrzeni nazw w bieżącej przestrzeni nazw, niezależnie od tego, czy trzeba/korzystania z nich. Z pewnością niepożądane.

Po drugie to using namespace declaration. Przywołuje tylko określoną nazwę symbolu w bieżącym obszarze nazw. Zaletą jest to, że za każdym razem nie trzeba wpisywać w pełni kwalifikowanej nazwy.

Trzeci to w pełni kwalifikowane nazwy tego symbolu. Wadą jest to, że musisz wpisać pełną nazwę wszędzie tam, gdzie używasz symbolu.

Najwyraźniej, drugie & Trzecie są bardziej odpowiednie. W żadnym z nich nie ma różnicy w wydajności. Jedyną różnicą jest ilość wprowadzanych znaków. Po prostu wybierz albo w zależności od tego, co określa twój standard kodowania.

Edycja:
jako @Jerry wskazuje stosując zgłoszenia w połączeniu z ADL (odnośników zależne argument) może prowadzić do niepożądanych efektów.
można znaleźć szczegółowe wyjaśnienia w jednym z moich odpowiedzi:

Detailed explanation on how Koenig lookup works with namespaces and why its a good thing?

sekcji,
Dlaczego krytyka Koenig algorytmu?

+0

I like like * using namespace declaration *, ponieważ mogę umieścić go w moim pliku .cpp i mam trochę listy, gdzie widzę "to jest używane z tych przestrzeni nazw w tym pliku", ale ja też lubię * w pełni kwalifikowany imiona * tak, jak mówią mi, gdy tylko widzę, że ta funkcjonalność pochodzi z tego obszaru nazw. Ale myślę, że robię to w jakimś miksie i z odpowiedzi, które zdobyłem, czuję się bezpiecznie, aby na tym nie poprzestać. Dziękuję za poświęcenie czasu na wyjaśnienie tego. – qrikko

+1

@qrikko: Zwykle należałoby przestrzegać standardów kodowania organizacji. W przeciwnym razie jest to osobisty wybór. Ważne jest, aby mieć konsekwencję po dokonaniu wyboru. –

+0

@qrikko: Niestety, jeśli przeczytasz moją odpowiedź, zdasz sobie sprawę, że 1) nie jesteś tak bezpieczny, jak myślisz, i 2) wszystkie odpowiedzi twierdzące, że nie ma żadnego wpływu na wydajność (pośrednio)) co najmniej potencjalnie błędne. Mają rację, że forma, w której podajesz nazwę, nie * bezpośrednio * wpływa na wydajność, ale wciąż jest błędna (lub wręcz sugeruje), że nie można jej wykonać. –

0

Głównym powodem jest to, że może to prowadzić do niejasności (zarówno dla kompilatora i dla ludzi czytnika) i to może również spowolnienie samą kompilację (ale to nie jest tak duży problem, ponieważ pierwszą rzeczą)

2

Nie ma wydajność zysk lub karę. Wszystkie wywołania i zmienne są rozwiązywane podczas kompilacji.

Wybór pomiędzy trzema jest nieco subiektywny. Tak, using namespace <ns>; jest czasami źle widziana, ponieważ zanieczyszcza globalną przestrzeń nazw, , ale Myślę, że jest bezpieczna w użyciu dla małych plików.

Zwykle używam drugiego do testowania, w którym spodziewam się konfliktów, ale później go usunę. Można to uzyskać Messiera, ponieważ może skończyć się z kombinacji obu wykwalifikowanych i un wykwalifikowanych nazwami:

vector<std::string> x; 

bo masz using std::vector; na górze, ale nie using std::string;.

Ja preferuję trzeci.

1

Występuje zerowy wpływ na wydajność kodu, jest to czysto kompilacja. Może to (teoretycznie) mieć wpływ na czasy kompilacji, ale wątpię, by kiedykolwiek osiągnął wymierne proporcje.

(lub jakakolwiek inna przestrzeń nazw w tym zakresie) zdecydowanie należy unikać w plikach nagłówkowych, które można umieścić w dowolnym miejscu, a wprowadzenie symboli w nich może spowodować niejasności.

Ogólnie rzecz biorąc istnieją przestrzenie nazw, aby uniknąć konfliktów nazw i using namespace niszczy ten cel. Tak samo w mniejszym stopniu jest using the_namespace::some_id. Nie ma jednoznacznej odpowiedzi na to pytanie, ale ja generalnie przestrzegać następujących zasad:

  1. Nigdy umieścić using namespace w pliku nagłówka.
  2. Unikaj using namespace i using, chyba że można zaoszczędzić olbrzymie ilości pisania. W razie potrzeby użyj aliasów przestrzeni nazw (to jest namespace abbrv = some_really::long_and::nested_namespace;).
  3. Spróbuj ograniczyć zakres using: możesz umieścić go w funkcjach i blokach, a także w obszarze nazw. Oznacza to, że jeśli posiadasz funkcję rejestrowania w pliku .cpp, wstaw using std::cout; i using std::endl; (lub cokolwiek innego używasz) do treści funkcji, a nie do zakresu plików.
4

Jest jeden (co prawda, nieco rzadkością) sytuacja, w której forma korzystania naprawdę może zrobić różnicę, a forma chcesz użyć jestusing namespace foo, i to najczęściej stosowany do nazw std (czyli gdzie piszesz using namespace std;.

najbardziej oczywistym przykładem jest to, że piszesz sortowania typu zdefiniowanego przez użytkownika. to możliwe że zostanie zastosowana do typu, dla którego użytkownik również zdefiniowany ma swoją własne swap.

Utkniesz w sytuacji, w której chcesz użyć swapu, jeśli go zdefiniowałeś, ale użyjesz std :: swap, jeśli go nie zdefiniował. Jeśli użyjesz std::swap bezpośrednio w kodzie, to skończysz używając std::swap, nawet jeśli typ ma zdefiniowaną własną zamianę. Odwrotnie, twój kod nie skompiluje się, jeśli bezpośrednio określisz swap specjalnie dla tego typu i żaden nie zostanie dostarczony.

Aby obejść ten problem, możesz zrobić coś takiego:

using namespace std; 

template <class Iter> 
void my_sort(Iter first, Iter last) { 
    // ... 
    if (*last < *first) 
     swap(*first, *last); 
} 

ten znajdzie swap specjalnie dla danego typu porównywanych (tj swap zdefiniowane w tej samej przestrzeni nazw, jak tego typu), jeżeli istnieje jeden (poprzez wyszukiwanie zależne od argumentu) i std::swap, jeśli żaden nie jest zdefiniowany dla typu (przez using namespace std;).

Może to mieć wpływ na wydajność - jeśli napisali swap specjalnie dla swojego typu, możesz ogólnie oczekiwać, że dzięki temu mogą zapewnić lepszą wydajność. Oznacza to, że jawne określenie std::swap może działać, ale prawdopodobnie doprowadzi do gorszej wydajności.

W przeciwnym razie jest to prawie wyłącznie kwestia wygody i czytelności - ja najczęściej wolę podawać pełne nazwy (np. std::swap) z wyjątkiem sytuacji jak powyżej, gdzie (w czasie, kiedy piszę kod) albo co najmniej dwie możliwości mogą być preferowane i chcę dać kompilatorowi wystarczającą swobodę wyboru właściwego.

Innym razem, gdy używam deklaracji/dyrektyw, przydatne jest, gdy przestrzenie nazw stają się naprawdę głęboko zagnieżdżone. Zwiększenie (dla jednego oczywistego przykładu) ma kilka nazw, które byłyby zbyt długie dla wygodnego użycia, jeśli używałbyś w pełni kwalifikowanej nazwy za każdym razem. Dotyczyło to szczególnie biblioteki Boost Lambda (teraz, na szczęście, w większości przestarzałej), w której użyłeś symboli zastępczych, takich jak _1, które skończyłyby się jako coś w rodzaju boost::lambda::placeholders::_1 (ale wychodzę z pamięci, więc prawdopodobnie jest to co najmniej częściowo błędne) jeśli nalegałeś na używanie w pełni kwalifikowanej nazwy. To pokonałoby dużą część celu używania biblioteki lambda w pierwszej kolejności.

+0

Jest tu kilka cennych informacji dodanych tutaj. Rzeczy, które należy wziąć pod uwagę, ponieważ w rzeczywistości są ** kwestią, która jest wyborem w tych przypadkach. Dziękuję za to. – qrikko

+2

Powiedziałbym jednak, że w tym przypadku wolisz używać 'using std :: swap;' –