Frage

Ein Merkmal von C ++ ist die Fähigkeit, unbenannte (anonym) Namespaces zu erstellen, etwa so:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

Sie würden denken, dass eine solche Funktion nutzlos wäre - da Sie nicht den Namen des Namespace angeben können, ist es unmöglich, etwas von außen in sie zugreifen zu können. Aber diese unbenannte Namensräume sind zugänglich innerhalb der Datei sie erstellt in, als ob Sie eine implizite using-Klausel zu ihnen hatte.

Meine Frage ist, warum oder wann würden es mit statischen Funktionen vorzuziehen? Oder sind sie im Wesentlichen zwei Möglichkeiten, die genau die gleiche Sache zu tun?

War es hilfreich?

Lösung

Die C ++ Standard-liest in Abschnitt 7.3.1.1 Unbenannt Namespaces, Absatz 2:

  

Die Verwendung des statischen Schlüsselwort   veraltet, wenn Objekte in einer Deklaration   Namespace-Rahmen, der ungenannte-Namespace   bietet eine überlegene Alternative.   

Static gilt nur für die Namen von Objekten, Funktionen und anonymen Gewerkschaften, nicht Erklärungen zu geben.

Edit:

Die Entscheidung, diese Verwendung des statischen Schlüsselwort deprecate (Affekt Sichtbarkeit einer Variablendeklaration in einer Übersetzungseinheit) umgekehrt wurde ( ref ). In diesem Fall wird eine statische oder eine unbenannte Namespace ist zurück im Wesentlichen zwei Möglichkeiten, um zu sein, genau dasselbe zu tun. Weitere Diskussion finden Sie unter diese Frage SO .

Unbenannt Namensräume haben noch den Vorteil, dass Sie Übersetzung einheits lokale Typen definieren. Bitte finden Sie unter diese SO Frage für weitere Details.

Kredit geht zu bringen, dies zu meiner Aufmerksamkeit Mike Percy .

Andere Tipps

Methoden in einem anonymen Namespace Putting verhindert, dass Sie versehentlich die Eine Definition Regel Sie erlaubt Sorgen nie Ihre Helfermethoden die gleiche wie eine andere Methode über die Benennung Sie verknüpfen in kann.

Und wie durch luke, anonyme Namespaces werden bevorzugt durch die Norm über statische Mitglieder hingewiesen.

Es gibt einen Fall, in dem Rand statisch eine überraschende Wirkung hat (zumindest für mich war). Die C ++ 03-Standard ist in 14.6.4.2/1:

  

Für einen Funktionsaufruf, der auf einem Template-Parametern abhängig ist, wenn der Name der Funktion ist ein unqualifizierte-id , aber nicht ein Template-id werden die Kandidaten Funktionen gefunden mit die üblichen Suchregeln (3.4.1, 3.4.2), außer dass:

     
      
  • Für den Teil der Lookup unqualifizierte Namen-Suche (3.4.1) verwendet, nur Funktionsdeklarationen mit externer Bindung aus dem Kontext Template-Definition zu finden sind.
  •   
  • Für den Teil der Lookup mit zugehörigem Namensraum (3.4.2), nur Funktionsdeklarationen mit externer Bindung entweder in dem Template-Definition gefunden Kontext oder die Vorlage Instanziierung Kontext gefunden werden.
  •   
     

...

Der Code unten wird foo(void*) anrufen und nicht foo(S const &) wie man erwarten könnte.

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

An sich ist dies wahrscheinlich nicht so große Sache, aber es hervorzuheben, dass für eine vollständig konforme C ++ Compiler (dh eine mit Unterstützung für export) die static Schlüsselwort wird noch Funktionalität haben, die nicht in irgendeiner anderen Art und Weise ist.

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

Der einzige Weg, um sicherzustellen, dass die Funktion in unserem unbenannte Namespace wird nicht in Vorlagen gefunden wird mit ADL zu machen, ist es static.

Update für moderne C ++

Wie von C ++ '11, Mitglieder eines ungenannten Namespace implizit interne Bindung haben (3,5 / 4):

  

Ein nicht namentlich genannten Namespace oder ein Namensraum direkt oder indirekt innerhalb eines ungenannten Namensraumes hat interne Bindung erklärt.

Aber zur gleichen Zeit wurde 14.6.4.2/1 aktualisiert Erwähnung der Verknüpfung zu entfernen (das von C ++ genommen '14):

  

Für einen Funktionsaufruf, wo der Postfix-Ausdruck eines abhängigen Name ist, werden die Kandidaten Funktionen gefunden mit   die üblichen Suchregeln (3.4.1, 3.4.2), außer dass:

     
      
  • Für den Teil der Lookup unqualifizierte Namen-Suche (3.4.1) verwendet, nur Funktionsdeklarationen aus dem Template-Definition Kontext gefunden werden.

  •   
  • Für den Teil der Lookup zugehörige Namensräume (3.4.2) verwendet, nur gefunden Funktionsdeklarationen entweder in dem Template-Definition Kontext oder die Vorlage Instanziierung Kontext gefunden werden.

  •   

Das Ergebnis ist, dass dieser besondere Unterschied zwischen statischen und unbenannte Namespace-Mitgliedern nicht mehr vorhanden ist.

Ich begann vor kurzem statische Keywords mit anonymen Namespaces in meinem Code zu ersetzen, sondern sofort in ein Problem lief, wo die Variablen im Namensraum nicht mehr zur Inspektion in meinem Debugger zur Verfügung standen. Ich war mit VC60, so dass ich weiß nicht, ob das ein Nicht-Thema mit anderen Debugger ist. Meine Abhilfe war ein ‚Modul‘ Namensraum zu definieren, wo ich den Namen meiner CPP-Datei gab.

Zum Beispiel in meiner XmlUtil.cpp Datei definiere ich einen Namespace XmlUtil_I {...} für alle meine Modul Variablen und Funktionen. So kann ich die XmlUtil_I :: Qualifikation im Debugger anwenden kann, um die Variablen zuzugreifen. In diesem Fall unterscheidet die ‚_I‘ es von einem öffentlichen Namensraum wie XMLUtil, die ich will kann an anderer Stelle verwenden.

Ich nehme an, ein möglicher Nachteil dieses Ansatzes zu einem wirklich anonym verglichen ist, dass jemand unter Verwendung des Namensraum-Qualifikationsspiel in anderen Modulen den gewünschten statischen Umfang verletzen könnte. Ich weiß nicht, ob das ein wichtiges Anliegen ist though.

Die Verwendung von statischem Schlüsselwort für diesen Zweck wird durch den C ++ 98-Standard veraltet. Das Problem bei statisch ist, dass es nicht Definition zu geben gilt. Es ist auch ein überlasteter Schlüsselwort auf unterschiedliche Weise in verschiedenen Kontexten verwendet, so unbenannte Namensräume vereinfachen die Dinge ein wenig.

Aus Erfahrung werde ich nur bemerken, dass, während es der C ++ Weg zu setzen früher statische Funktionen in den anonymen Namespace, ältere Compiler manchmal Probleme damit haben. Ich arbeite zur Zeit mit einigen Compilern für unsere Zielplattformen und der moderneren Linux-Compiler ist in Ordnung mit Funktionen in den anonymen Namespace platzieren.

Aber ein älterer Compiler auf Solaris, die wir bis eine unbestimmte Zukunft Release vermählen werden, wird es manchmal akzeptieren, und andere Zeiten markieren es als Fehler. Der Fehler ist nicht das, was mir Sorgen macht, ist es, was es könnte tun, wenn es akzeptiert es. Also, bis wir auf der ganzen Linie moderne gehen, sind wir immer noch statisch (in der Regel Klasse-scoped) Funktionen, bei denen wir den anonymen Namespace bevorzugen würden.

Außerdem, wenn man verwendet statisches Schlüsselwort auf einer Variable wie in diesem Beispiel:

namespace {
   static int flag;
}

Es wäre in der Zuordnungsdatei nicht gesehen werden

Sie sind gerade jetzt nur diese Funktion gelernt, während der Frage zu lesen, kann ich nur spekulieren. Dies scheint mehrere Vorteile gegenüber einer Dateiebene statischen Variablen zu liefern:

  • Anonyme Namespaces können ineinander und bietet mehrere Schutzebenen verschachtelt werden, aus denen Symbole nicht entweichen kann.
  • Mehrere anonyme Namespaces in der gleichen Quelldatei angeordnet werden könnte, in der Tat unterschiedliche statische Ebene Bereiche innerhalb der gleichen Datei.

würde ich beim Lernen interessiert, wenn jemand anonyme Namespaces in echtem Code verwendet wird.

Ein Compiler spezifischer Unterschied zwischen anonymen Namespaces und statischen Funktionen kann Kompilieren Sie den folgenden Code zu sehen.

#include <iostream>

namespace
{
    void unreferenced()
    {
        std::cout << "Unreferenced";
    }

    void referenced()
    {
        std::cout << "Referenced";
    }
}

static void static_unreferenced()
{
    std::cout << "Unreferenced";
}

static void static_referenced()
{
    std::cout << "Referenced";
}

int main()
{
    referenced();
    static_referenced();
    return 0;
}

Kompilieren diesen Code mit VS 2017 (die Ebene 4 Warnflag Spezifizierungs / W4 c4505 Warnung: unreferenced lokale Funktion entfernt wurde ) und gcc 4.9 mit der -Wunused-Funktion oder -Wall flag zeigt, dass VS 2017 nur produzieren eine Warnung für die nicht genutzte statische Funktion. gcc 4.9 und höher, sowie Klirren 3.3 und höher, werden Warnungen für die nicht referenzierte Funktion im Namensraum erzeugen und auch eine Warnung für die nicht genutzte statische Funktion.

Live-Demo von gcc 4.9 und MSVC 2017

Persönlich bevorzuge ich statische Funktionen über namenlos Namensräume aus den folgenden Gründen:

  • es ist offensichtlich und klar von Funktionsdefinition allein, dass es an die Übersetzungseinheit privat ist, wo es kompiliert. Mit namesless Namespace müssen Sie möglicherweise scrollen und um zu sehen, zu suchen, wenn eine Funktion in einem Namensraum ist.

  • Funktionen in Namensräumen könnten von einigen (älteren) Compiler als extern behandelt werden. In VS2017 sind sie immer noch extern. Aus diesem Grund, selbst wenn eine Funktion in namenlos Namespace können Sie immer noch sie statisch markieren möchten.

  • statische Funktionen verhalten sich sehr ähnlich in C oder C ++, während namenlos Namespaces offensichtlich C ++ nur. namenlos Namespaces auch zusätzliche Ebene hinzufügen, wenn Vertiefung und Ich mag es nicht, dass:)

Also, ich bin glücklich, dass die Verwendung von statischen für Funktionen finden Sie unter wird nicht mehr veraltet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top