Dlaczego używane są nienazwane przestrzenie nazw i jakie są ich zalety?
Właśnie dołączyłem do nowego projektu oprogramowania C++ i staram się zrozumieć projekt. Projekt często korzysta z nienazwanych przestrzeni nazw. Na przykład, coś takiego może wystąpić w pliku definicji klasy:
// newusertype.cc
namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;
bool getState(userType*,otherUserType*);
}
newusertype::newusertype(...) {...
Jakie są względy projektowe, które mogą spowodować użycie nienazwanej przestrzeni nazw? Jakie są zalety i wady?
6 answers
(w dalszej części, przekreślone rzeczy są rzeczy, które nie mają zastosowania do C++11, ale mają zastosowanie do C++03. C++11 nie czyni już prawie żadnych różnic (jeśli są, to są to po prostu różnice językowe, których nie pamiętam).).
Unnamed namespaces are a utility to make a identifier effective translation unit local. Zachowują się tak, jakbyś wybrał unikalną nazwę dla jednostki tłumaczeniowej dla przestrzeni nazw:
namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }
Dodatkowy krok użycie pustego ciała jest ważne, więc można już odwoływać się w obrębie ciała przestrzeni nazw do identyfikatorów takich jak ::name
, które są zdefiniowane w tej przestrzeni nazw, ponieważ dyrektywa using już miała miejsce.
Oznacza to, że możesz mieć wolne funkcje o nazwie (na przykład) help
, które mogą istnieć w wielu jednostkach translacyjnych i nie będą się ze sobą kolidować w czasie połączenia, ponieważ wszystkie mają unikalną nazwę ze względu na ich unikalną przestrzeń nazw, w której się znajdują. Efekt jest prawie identyczny jak przy użyciu static
słowo kluczowe użyte w C, które można umieścić w deklaracji identyfikatorów. nienazwane przestrzenie nazw są lepszą alternatywą, będąc w stanie nawet uczynić jednostkę tłumaczenia typu lokalną. static
używane w ten sposób jest przestarzałe w C++, ponieważ
namespace { int a1; }
static int a2;
Oba a
są lokalne i nie kolidują w czasie połączenia. Ale różnica polega na tym, że a1
w anonimowej przestrzeni nazw po prostu otrzymuje unikalną nazwę. ma jeszcze zewnętrzne powiązania i może być eksportowany do tabela symboli tworzonego pliku obiektowego. Staje się to ważne, jeśli chcesz użyć jego adresu jako argumentu szablonu:
template<int * ptr> struct sample { };
// OK - a1 has external linkage
sample<&a1> s1;
// NOT OK - translation unit locality is done by giving a2 internal linkage.
sample<&a2> s2;
Parametry szablonu muszą mieć zewnętrzne powiązanie, więc w tym przypadku identyfikator musi być umieszczony w anonimowej przestrzeni nazw.
Przeczytaj doskonały artykuł w comeau-computing `Dlaczego zamiast statycznej używa się nienazwanej przestrzeni nazw?.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-29 19:45:44
Posiadanie czegoś w anonimowej przestrzeni nazw oznacza, że jest ono lokalne dla tejjednostki tłumaczeniowej (.oznacza to, że jeśli inny symbol o tej samej nazwie zostanie zdefiniowany gdzie indziej, nie będzie naruszenia jednej reguły definicji (ODR).
Jest to ten sam sposób, w jaki C ma statyczną zmienną globalną lub statyczną funkcję, ale może być również używany do definicji klas (I powinien być używany zamiast static
W C++).
Wszystkie anonimowe przestrzenie nazw w tym samym pliku są traktowane jako ta sama przestrzeń nazw, a wszystkie anonimowe przestrzenie nazw w różnych plikach są różne. Anonimowa przestrzeń nazw jest odpowiednikiem:
namespace __unique_compiler_generated_identifer0x42 {
...
}
using namespace __unique_compiler_generated_identifer0x42;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-01 22:37:07
Przykład pokazuje, że ludzie w projekcie, do którego dołączyłeś, nie rozumieją anonimowych przestrzeni nazw:)
namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;
Nie muszą one znajdować się w anonimowej przestrzeni nazw, ponieważ const
obiekt ma już statyczne powiązanie i dlatego nie może być w konflikcie z identyfikatorami o tej samej nazwie w innej jednostce tłumaczeniowej.
bool getState(userType*,otherUserType*);
}
I to jest właściwie pesymizacja: getState()
mA zewnętrzne powiązania. Zwykle lepiej jest preferować statyczne połączenie, ponieważ nie zanieczyszcza to tabeli symboli. Lepiej napisać
static bool getState(/*...*/);
Tutaj. Wpadłem w tę samą pułapkę( w standardzie jest sformułowanie sugerujące, że statyka plików jest w jakiś sposób przestarzała na rzecz anonimowych przestrzeni nazw), ale pracując w dużym projekcie C++, takim jak KDE, masz wielu ludzi, którzy znowu odwracają głowę:) {]}Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-24 17:20:04
Oprócz innych odpowiedzi na to pytanie, korzystanie z anonimowej przestrzeni nazw może również poprawić wydajność. Ponieważ symbole w przestrzeni nazw nie wymagają żadnego zewnętrznego powiązania, kompilator ma większą swobodę w przeprowadzaniu agresywnej optymalizacji kodu w przestrzeni nazw. Na przykład funkcja, która jest wywoływana wielokrotnie raz w pętli, może być inlinowana bez żadnego wpływu na rozmiar kodu.
Na przykład w moim systemie poniższy kod zajmuje około 70% czasu uruchamiania, jeśli używana jest anonimowa przestrzeń nazw (x86-64 gcc-4.6.3 i-O2; zauważ, że dodatkowy kod w add_val sprawia, że kompilator nie chce dołączać go dwa razy).
#include <iostream>
namespace {
double a;
void b(double x)
{
a -= x;
}
void add_val(double x)
{
a += x;
if(x==0.01) b(0);
if(x==0.02) b(0.6);
if(x==0.03) b(-0.1);
if(x==0.04) b(0.4);
}
}
int main()
{
a = 0;
for(int i=0; i<1000000000; ++i)
{
add_val(i*1e-10);
}
std::cout << a << '\n';
return 0;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-29 09:34:53
Anonimowa przestrzeń nazw tworzy zamknięte zmienne, funkcje, klasy itp. dostępne tylko w tym pliku. W twoim przykładzie jest to sposób na uniknięcie zmiennych globalnych. Nie ma różnicy w wydajności w czasie wykonywania ani kompilacji.
Nie ma tak wiele zalet lub wad poza "czy chcę tę zmienną, funkcję, klasę, itp. być publicznym czy prywatnym?"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-10 21:19:28
Nienazwana przestrzeń nazw ogranicza dostęp klasy, zmiennej, funkcji i obiektów do pliku, w którym jest zdefiniowana. Funkcjonalność nienazwanej przestrzeni nazw jest podobna do słowa kluczowego static
w C / C++.static
słowo kluczowe ogranicza dostęp zmiennej globalnej i funkcji do pliku, w którym są zdefiniowane.
Istnieje różnica między nienazwaną przestrzenią nazw a słowem kluczowym static
, dzięki czemu nienazwana przestrzeń nazw ma przewagę nad statyczną. static
słowo kluczowe może być używane ze zmienną, funkcją i obiektami, ale nie z użytkownikiem zdefiniowana Klasa.
Na przykład:
static int x; // Correct
Ale,
static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong
Ale to samo może być możliwe z nienazwaną przestrzenią nazw. Na przykład,
namespace {
class xyz {/*Body of class*/}
static structure {/*Body of structure*/}
} //Correct
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-10 00:21:40