it-swarm.com.de

Warum werden unbenannte Namespaces verwendet und welche Vorteile bieten sie?

Ich bin gerade einem neuen C++ - Softwareprojekt beigetreten und versuche, das Design zu verstehen. Das Projekt verwendet häufig unbenannte Namespaces. So etwas kann beispielsweise in einer Klassendefinitionsdatei auftreten:

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

Welche Überlegungen zum Entwurf können dazu führen, dass ein nicht benannter Namespace verwendet wird? Was sind die Vor- und Nachteile?

215
Scottie T

(Im Folgenden handelt es sich um Dinge, die für C++ 11 nicht mehr zutreffen, für C++ 03 jedoch nicht mehr. C++ 11 macht fast keine Unterschiede mehr (wenn ja, handelt es sich nur noch um Unterschiede zwischen Sprachanwälten, die es gibt) Ich kann mich nicht erinnern).).

Unbenannte Namespaces sind ein Hilfsprogramm, um eine ID-Übersetzungseinheit lokal zu machen. Sie verhalten sich so, als würden Sie einen eindeutigen Namen pro Übersetzungseinheit für einen Namespace wählen:

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

Der zusätzliche Schritt zur Verwendung des leeren Körpers ist wichtig, sodass Sie bereits innerhalb des Namespace-Körpers auf Bezeichner wie ::name Verweisen können, die in diesem Namespace definiert sind, da die using-Direktive bereits stattgefunden hat.

Dies bedeutet, dass Sie freie Funktionen namens (zum Beispiel) help haben können, die in mehreren Übersetzungseinheiten vorhanden sein können, und dass sie zum Zeitpunkt der Verknüpfung nicht kollidieren. Der Effekt ist fast identisch mit der Verwendung des in C verwendeten Schlüsselworts static, das Sie in die Deklaration der Bezeichner einfügen können. Unbenannte Namespaces sind eine überlegene Alternative, da sie sogar eine Typübersetzungseinheit lokal machen können.

namespace { int a1; }
static int a2;

Beide a sind lokale Übersetzungseinheiten und stoßen zum Zeitpunkt der Verknüpfung nicht zusammen. Der Unterschied besteht jedoch darin, dass das a1 Im anonymen Namespace einen eindeutigen Namen erhält.

Lesen Sie den hervorragenden Artikel bei comeau-computing Warum wird anstelle von statisch ein unbenannter Namespace verwendet? ( Archive.org-Spiegel ).

171

Wenn sich etwas in einem anonymen Namespace befindet, ist es lokal für diese Übersetzungseinheit (CPP-Datei und alle zugehörigen Includes). Wenn ein anderes Symbol mit demselben Namen an einer anderen Stelle definiert wird, liegt kein Verstoß gegen die vor One Definition Rule (ODR).

Dies entspricht der C-Methode für eine statische globale Variable oder eine statische Funktion, kann jedoch auch für Klassendefinitionen verwendet werden (und sollte in C++ anstelle von static verwendet werden).

Alle anonymen Namespaces in derselben Datei werden als derselbe Namespace behandelt, und alle anonymen Namespaces in verschiedenen Dateien sind unterschiedlich. Ein anonymer Namespace entspricht:

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;
63
Motti

Das Beispiel zeigt, dass die Personen in dem Projekt, dem Sie beigetreten sind, anonyme Namespaces nicht verstehen :)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

Diese müssen sich nicht in einem anonymen Namespace befinden, da const -Objekt bereits statisch verknüpft ist und daher möglicherweise keine Konflikte mit gleichnamigen Bezeichnern in einer anderen Übersetzungseinheit auftreten können.

    bool getState(userType*,otherUserType*);
}

Und das ist eigentlich eine Pessimisierung: getState() hat eine externe Verknüpfung. Es ist normalerweise besser, statische Verknüpfungen zu bevorzugen, da dies die Symboltabelle nicht verschmutzt. Es ist besser zu schreiben

static bool getState(/*...*/);

hier. Ich bin in die gleiche Falle geraten (es gibt Formulierungen im Standard, die darauf hindeuten, dass Dateistatiken zugunsten anonymer Namespaces veraltet sind), aber bei der Arbeit in einem großen C++ - Projekt wie KDE gibt es viele Leute, die den Kopf in die richtige Richtung drehen wieder da :)

12

Zusätzlich zu den anderen Antworten auf diese Frage kann die Verwendung eines anonymen Namespaces auch die Leistung verbessern. Da Symbole im Namespace keine externe Verknüpfung benötigen, kann der Compiler den Code im Namespace aggressiver optimieren. Beispielsweise kann eine Funktion, die in einer Schleife mehrfach aufgerufen wird, ohne Auswirkung auf die Codegröße eingefügt werden.

Beispiel: Auf meinem System benötigt der folgende Code ungefähr 70% der Laufzeit, wenn der anonyme Namespace verwendet wird (x86-64 gcc-4.6.3 und -O2; beachten Sie, dass der Compiler den zusätzlichen Code in add_val nicht einschließen möchte es zweimal).

#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;
}
12
xioxox

Ein anonymer Namespace stellt die eingeschlossenen Variablen, Funktionen, Klassen usw. nur in dieser Datei zur Verfügung. In Ihrem Beispiel können so globale Variablen vermieden werden. Es gibt keinen Laufzeit- oder Kompilierungszeitunterschied.

Abgesehen von "Soll diese Variable, Funktion, Klasse usw. öffentlich oder privat sein?" Gibt es nicht so viele Vor- oder Nachteile.

11
Max Lybbert

Ein unbenannter Namespace begrenzt den Zugriff von Klasse, Variable, Funktion und Objekten auf die Datei, in der er definiert ist. Die Funktionalität für unbenannte Namespaces ähnelt dem Schlüsselwort static in C/C++.
Das Schlüsselwort static beschränkt den Zugriff auf globale Variablen und Funktionen auf die Datei, in der sie definiert sind.
Es gibt einen Unterschied zwischen unbenanntem Namespace und dem Schlüsselwort static, aufgrund dessen unbenannter Namespace gegenüber statischem Vorteil hat. Das Schlüsselwort static kann mit Variablen, Funktionen und Objekten verwendet werden, jedoch nicht mit benutzerdefinierten Klassen.
Beispielsweise:

static int x;  // Correct 

Aber,

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

Dies kann jedoch auch mit einem unbenannten Namespace möglich sein. Beispielsweise,

 namespace {
           class xyz {/*Body of class*/}
           static structure {/*Body of structure*/}
  } //Correct
9
Sachin