Cechą C ++ jest możliwość tworzenia nienazwanych (anonimowych) przestrzeni nazw, takich jak:
namespace {
int cannotAccessOutsideThisFile() { ... }
} // namespace
Można by pomyśleć, że taka funkcja byłaby bezużyteczna - ponieważ nie można podać nazwy przestrzeni nazw, nie można uzyskać do niej dostępu z zewnątrz. Ale te nienazwane przestrzenie nazw są dostępne w pliku, w którym zostały utworzone, tak jakbyś miał dla nich niejawną klauzulę use.
Moje pytanie brzmi: dlaczego lub kiedy byłoby to lepsze niż używanie funkcji statycznych? Czy są to zasadniczo dwa sposoby robienia dokładnie tego samego?
c++
namespaces
Head Geek
źródło
źródło
static
w tym kontekście było nieaktualne ; chociaż nienazwana przestrzeń nazw jest doskonałą alternatywą dlastatic
, istnieją przypadki, w których zawodzi, gdystatic
przychodzi na ratunek .Odpowiedzi:
Standard C ++ czyta się w sekcji 7.3.1.1 Nienazwane przestrzenie nazw, akapit 2:Statyczne dotyczy tylko nazw obiektów, funkcji i anonimowych związków, a nie deklaracji typów.
Edytować:
Decyzja o wycofaniu tego użycia statycznego słowa kluczowego (wpływa na widoczność deklaracji zmiennej w jednostce tłumaczeniowej) została cofnięta ( odwołanie ). W tym przypadku użycie statycznej lub nienazwanej przestrzeni nazw powraca do bycia zasadniczo dwoma sposobami wykonania dokładnie tego samego. Aby uzyskać więcej dyskusji, zobacz to SO pytanie.
Nienazwane przestrzenie nazw mają tę zaletę, że pozwalają definiować typy jednostek lokalnych tłumaczących. Zobacz to SO pytanie, aby uzyskać więcej informacji.
Podziękowania należą się Mike'owi Percy'emu za zwrócenie mi na to uwagi.
źródło
namespace
s domyślnie mają wewnętrzne powiązanie, więc nie powinno być różnicy. Wszelkie problemy, które mogły wcześniej wynikać z niewłaściwego sformułowania, zostały rozwiązane poprzez uczynienie tego wymaganiem w C ++ 11.Umieszczenie metod w anonimowej przestrzeni nazw zapobiega przypadkowemu naruszeniu reguły One Definition , pozwalając nigdy nie martwić się nazwaniem metod pomocniczych tak samo, jak innymi metodami, do których można się połączyć.
I, jak zauważył Luke, anonimowe przestrzenie nazw są preferowane przez standard nad elementami statycznymi.
źródło
Jest jeden przypadek krawędzi, w którym statyczny ma zaskakujący efekt (przynajmniej dla mnie). Norma C ++ 03 stwierdza w 14.6.4.2/1:
Poniższy kod zadzwoni
foo(void*)
i niefoo(S const &)
tak, jak można się spodziewać.Samo w sobie prawdopodobnie nie jest to wielka sprawa, ale podkreśla, że dla w pełni zgodnego kompilatora C ++ (tj. Z obsługą
export
)static
słowo kluczowe nadal będzie miało funkcjonalność, która nie będzie dostępna w żaden inny sposób.Jedynym sposobem, aby upewnić się, że funkcja w naszym nienazwanym obszarze nazw nie zostanie znaleziona w szablonach korzystających z ADL, to zrobić to
static
.Aktualizacja dla Modern C ++
Począwszy od C ++ '11, członkowie nienazwanej przestrzeni nazw mają niejawnie wewnętrzne powiązanie (3.5 / 4):
Ale jednocześnie 14.6.4.2/1 został zaktualizowany, aby usunąć wzmiankę o powiązaniu (wzięte z C ++ '14):
W rezultacie ta szczególna różnica między statycznymi i nienazwanymi elementami przestrzeni nazw już nie istnieje.
źródło
NS::S
żeby pracować, nieS
musisz być w środkunamespace {}
?Niedawno zacząłem zastępować statyczne słowa kluczowe anonimowymi przestrzeniami nazw w moim kodzie, ale od razu natknąłem się na problem polegający na tym, że zmienne w przestrzeni nazw nie były już dostępne do kontroli w moim debuggerze. Korzystałem z VC60, więc nie wiem, czy nie jest to problem z innymi debuggerami. Moim obejściem było zdefiniowanie przestrzeni nazw „modułu”, w której nadałem jej nazwę mojego pliku CPP.
Na przykład w moim pliku XmlUtil.cpp definiuję przestrzeń nazw
XmlUtil_I { ... }
dla wszystkich moich zmiennych modułu i funkcji. W ten sposób mogę zastosowaćXmlUtil_I::
kwalifikację w debuggerze, aby uzyskać dostęp do zmiennych. W tym przypadku_I
odróżnia go od publicznej przestrzeni nazw, takiej jakXmlUtil
której mogę chcieć użyć gdzie indziej.Podejrzewam, że potencjalną wadą tego podejścia w porównaniu z prawdziwie anonimowym jest to, że ktoś może naruszyć pożądany zakres statyczny, używając kwalifikatora przestrzeni nazw w innych modułach. Nie wiem jednak, czy to poważny problem.
źródło
#if DEBUG namespace BlahBlah_private { #else namespace { #endif
, więc „przestrzeń nazw modułów” jest obecna tylko w kompilacjach debugowania, a prawdziwa anonimowa przestrzeń nazw jest używana w inny sposób. Byłoby miło, gdyby debuggery dawały dobry sposób na poradzenie sobie z tym. Doxygen też się tym myli.Używanie statycznego słowa kluczowego do tego celu jest przestarzałe w standardzie C ++ 98. Problem ze statycznym polega na tym, że nie dotyczy definicji typu. Jest to również przeciążone słowo kluczowe używane na różne sposoby w różnych kontekstach, więc nienazwane przestrzenie nazw nieco upraszczają sprawę.
źródło
Z doświadczenia zauważę tylko, że chociaż jest to sposób C ++ do umieszczania funkcji statycznych w anonimowej przestrzeni nazw, starsze kompilatory mogą czasem mieć z tym problemy. Obecnie pracuję z kilkoma kompilatorami dla naszych platform docelowych, a nowocześniejszy kompilator Linux jest w porządku, umieszczając funkcje w anonimowej przestrzeni nazw.
Ale starszy kompilator działający w systemie Solaris, do którego jesteśmy zobowiązani do nieokreślonej przyszłej wersji, czasami go zaakceptuje, a innym razem oznaczy go jako błąd. Błąd nie jest tym, co mnie martwi, ale to, co może robić, kiedy to zaakceptuje . Tak więc, dopóki nie przejdziemy na nowo, nadal używamy funkcji statycznych (zwykle o zasięgu klasowym), w których wolelibyśmy anonimową przestrzeń nazw.
źródło
Ponadto, jeśli używa się słowa kluczowego static na zmiennej takiej jak ten przykład:
Nie będzie go widać w pliku odwzorowania
źródło
Różnica charakterystyczna dla kompilatora między anonimowymi przestrzeniami nazw a funkcjami statycznymi jest widoczna podczas kompilowania następującego kodu.
Kompilowanie tego kodu z VS 2017 (określenie flagi ostrzeżenia poziomu 4 / W4 w celu włączenia ostrzeżenia C4505: usunięto niereferencyjną funkcję lokalną ), a gcc 4.9 z opcją -Wunused-function lub -Wall flag pokazuje, że VS 2017 wygeneruje tylko ostrzeżenie dla nieużywana funkcja statyczna. gcc 4.9 i wyższe, a także clang 3.3 i wyższe, będą generować ostrzeżenia dla funkcji, do których nie ma odniesienia w przestrzeni nazw, a także ostrzeżenie dla nieużywanej funkcji statycznej.
Demo na żywo z gcc 4.9 i MSVC 2017
źródło
Osobiście wolę funkcje statyczne niż bezimienne przestrzenie nazw z następujących powodów:
Z samej definicji funkcji jest oczywiste i jasne, że jest prywatna dla jednostki tłumaczącej, w której jest skompilowana. W przypadku bezimiennej przestrzeni nazw konieczne może być przewijanie i wyszukiwanie w celu sprawdzenia, czy funkcja znajduje się w przestrzeni nazw.
Funkcje w obszarach nazw mogą być traktowane jako zewnętrzne przez niektóre (starsze) kompilatory. W VS2017 są jeszcze zewnętrzni. Z tego powodu nawet jeśli funkcja znajduje się w bezimiennej przestrzeni nazw, nadal możesz chcieć oznaczyć ją jako statyczną.
Funkcje statyczne zachowują się bardzo podobnie w C lub C ++, podczas gdy bezimienne przestrzenie nazw są oczywiście tylko C ++. Bezimienne przestrzenie nazw dodają dodatkowy poziom wcięcia i nie podoba mi się to :)
Dlatego cieszę się, że użycie funkcji statycznych dla funkcji nie jest już przestarzałe .
źródło
static
słowo kluczowe faktycznie stosuje lokalne powiązanie z funkcją. Czy na pewno tylko szalony szaleniec rzeczywiście dodałby wcięcia w przestrzeni nazw?Po zapoznaniu się z tą funkcją dopiero teraz, czytając twoje pytanie, mogę tylko spekulować. Wydaje się, że zapewnia to szereg korzyści w porównaniu ze zmienną statyczną na poziomie pliku:
Chciałbym dowiedzieć się, czy ktoś używał anonimowych przestrzeni nazw w prawdziwym kodzie.
źródło
Różnica polega na nazwie zniekształconego identyfikatora (
_ZN12_GLOBAL__N_11bE
vs_ZL1b
, co tak naprawdę nie ma znaczenia, ale oba są połączone z symbolami lokalnymi w tabeli symboli (brak.global
dyrektywy asm).Jeśli chodzi o zagnieżdżoną anonimową przestrzeń nazw:
Wszystkie anonimowe przestrzenie nazw pierwszego poziomu w jednostce tłumaczeniowej są ze sobą łączone, Wszystkie zagnieżdżone anonimowe przestrzenie nazw pierwszego poziomu w jednostce tłumaczącej są ze sobą łączone
Możesz także mieć zagnieżdżoną (wbudowaną) przestrzeń nazw w anonimowej przestrzeni nazw
Możesz także mieć anonimowe wbudowane przestrzenie nazw, ale o ile wiem,
inline
na anonimowej przestrzeni nazw ma 0 wpływ_ZL1b
:_Z
oznacza, że jest to zniekształcony identyfikator.L
oznacza, że jest to symbol lokalny przezstatic
.1
jest długością identyfikatora,b
a następnie identyfikatoremb
_ZN12_GLOBAL__N_11aE
_Z
oznacza, że jest to zniekształcony identyfikator.N
oznacza, że to przestrzeń nazw12
jest długością anonimowej nazwy przestrzeni nazw_GLOBAL__N_1
, następnie anonimowa nazwa przestrzeni nazw_GLOBAL__N_1
, a następnie1
długość identyfikatoraa
,a
jest identyfikatorema
iE
zamyka identyfikator znajdujący się w przestrzeni nazw._ZN12_GLOBAL__N_11A1aE
jest taki sam jak powyżej, ale zawiera inny poziom przestrzeni nazw1A
źródło