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?

Author: James McNellis, 2008-12-10

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. static używane w ten sposób jest przestarzałe w C++, ponieważ nienazwane przestrzenie nazw są lepszą alternatywą, będąc w stanie nawet uczynić jednostkę tłumaczenia typu lokalną.

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

 154
Author: Johannes Schaub - litb,
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;
 54
Author: Motti,
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ę:) {]}
 12
Author: Marc Mutz - mmutz,
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;
}
 11
Author: xioxox,
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?"

 8
Author: Max Lybbert,
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
 5
Author: Sachin,
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