Standard-Namespace verwenden

110

Es scheint unterschiedliche Ansichten zur Verwendung von 'using' in Bezug auf den Standard-Namespace zu geben.

Einige sagen "benutze" using namespace std, andere sagen "nicht", sondern stellen std-Funktionen voran, die mit " std::" verwendet werden sollen, während andere sagen, benutze so etwas:

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;

für alle Standardfunktionen, die verwendet werden sollen.

Was sind die Vor- und Nachteile von jedem?

paoloricardo
quelle

Antworten:

131

Die meisten C ++ Benutzer sind sehr glücklich , Lesen std::string, std::vectoretc. In der Tat, ein rohes zu sehen vectormacht mich fragen , ob dies das ist std::vectoroder ein anderer benutzerdefiniert vector.

Ich bin immer gegen die Verwendung using namespace std; . Es importiert alle Arten von Namen in den globalen Namespace und kann alle möglichen nicht offensichtlichen Mehrdeutigkeiten verursachen.

Hier sind einige gebräuchliche Bezeichner, die sich im stdNamespace befinden: count, sort, find, same, reverse. Nachdem eine lokale Variable namens countMittel , die using namespace stdnicht ermöglichen wird , den Sie verwenden countstatt std::count.

Das klassische Beispiel für einen unerwünschten Namenskonflikt lautet wie folgt. Stellen Sie sich vor, Sie sind Anfänger und wissen nichts darüber std::count. Stellen Sie sich vor, Sie verwenden entweder etwas anderes <algorithm>oder es wurde von einem scheinbar nicht verwandten Header eingezogen.

#include <algorithm>
using namespace std;

int count = 0;

int increment()
{
    return ++count; // error, identifier count is ambiguous
}

Der Fehler ist normalerweise lang und unfreundlich, da std::countes sich um eine Vorlage mit einigen langen verschachtelten Typen handelt.

Dies ist jedoch in Ordnung, da es std::countin den globalen Namespace geht und die Funktionsanzahl ihn verbirgt.

#include <algorithm>
using namespace std;

int increment()
{
    static int count = 0;
    return ++count;
}

Vielleicht etwas überraschend, das ist OK. In einen deklarativen Bereich importierte Bezeichner werden im gemeinsamen Namespace angezeigt, der sowohl den Ort enthält, an dem sie definiert sind, als auch den Ort, an den sie importiert werden. Mit anderen Worten, std::countist sichtbar wie countim globalen Namespace, jedoch nur innerhalb increment.

#include <algorithm>

int increment()
{
    using namespace std;
    static int count = 0;
    return ++count;
}

Und aus ähnlichen Gründen countist hier nicht eindeutig. using namespace stdnicht verursachen std::count, verstecken Sie das Äußere, countwie es zu erwarten war. Die using namespaceRegel bedeutet, dass sie std::count(in der incrementFunktion) so aussieht, als ob sie im globalen Bereich deklariert wurde, dh im selben Bereich wie int count = 0;und damit die Mehrdeutigkeit verursacht.

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}
CB Bailey
quelle
21
aber es tippt soooo viel einfacher ohne das std :: Präfix!
xtofl
69
@xtofl: Nein, das tut es nicht. Fünf Zeichen sind beim Tippen nicht so relevant, aber diese fünf Zeichen können beim Lesen sehr relevant sein. Und das einfache Lesen zählt viel mehr als das einfache Eingeben von Quellcode, da Code viel mehr gelesen als geschrieben wird.
sbi
3
Sie können hinzufügen, dass sich die using-Anweisung mit Bereichsregeln korrekt verhält.
Martin York
2
@ Martin York: Aktualisiert mit Beispielen zur Veranschaulichung der Gültigkeitsbereichsregeln. @ Michael Burr: Das ist wohl nicht so schlimm. Was ich wirklich nicht mag, ist, wo die Fehlermeldungen für einfache Fehler viel schwerer zu interpretieren sind oder wo sie überhaupt nicht auftreten. Wenn beispielsweise angenommen wird, dass eine Funktion im Gültigkeitsbereich liegt, dies jedoch nicht der Fall ist und eine std :: -Funktion nicht den hilfreichen Fehler "Bezeichner nicht erkannt" erhält, wird häufig ein dunkleres Argument angezeigt, das das Argument nicht konvertieren kann X 'oder' Funktion kann nicht aus Vorlage generiert werden 'Stilfehler. Schlimmer ist, wenn eine falsche Funktion stillschweigend aufgerufen wird. Es ist selten, aber es passiert.
CB Bailey
5
Nun, ich bin überrascht, dass niemand über die Option von diskutiert hat using std::xxx;. Es verschmutzt keinen Namespace, das Schreiben von Code wird kürzer und ich denke, es copyist viel lesbarer als std::copy.
Legends2k
41

Ausschluss der Grundlagen (Sie müssen std :: vor allen stl-Objekten / -Funktionen hinzufügen und haben weniger Konfliktwahrscheinlichkeit, wenn Sie nicht den Namespace std verwenden).

Es ist auch erwähnenswert, dass Sie nie setzen sollten

using namespace std

In einer Header-Datei, da sie an alle Dateien weitergegeben werden kann, die diese Header-Datei enthalten, auch wenn sie diesen Namespace nicht verwenden möchten.

In einigen Fällen ist es sehr vorteilhaft, Dinge wie zu verwenden

using std::swap

Als ob es eine spezielle Version von Swap gibt, wird der Compiler diese verwenden, andernfalls wird darauf zurückgegriffen std::swap.

Wenn Sie anrufen std::swap, verwenden Sie immer die Basisversion, die die optimierte Version nicht aufruft (falls vorhanden).

Yacoby
quelle
10
+1 zum Erwähnen using std::swap(was das einzige ist, was ich jemals benutze).
sbi
1
+1 für die Erwähnung, dass u n ssich ausbreiten kann. Nur um zu beachten, dass es sich auch in korrekt konstruierte Header einschleichen kann: Sie müssen nur nach einem Rogue-Header eingefügt werden.
Quamrana
1
Aber wenn Sie definieren eine swapoder move(oder hash, lessetc.) Spezialisierung, sollten Sie diese Spezialisierung in sein Putting namespace stdsowieso. Zum Beispiel:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
AJMansfield
28

Zunächst einige Begriffe:

  • using-Deklaration : using std::vector;
  • using-Direktive : using namespace std;

Ich denke, dass die Verwendung von using-Direktiven in Ordnung ist, solange sie nicht im globalen Bereich einer Header-Datei verwendet werden. Also haben

using namespace std;

in Ihrer CPP-Datei ist kein wirkliches Problem, und wenn sich herausstellt, dass es vollständig unter Ihrer Kontrolle steht (und es kann auf Wunsch sogar auf bestimmte Blöcke beschränkt werden). Ich sehe keinen besonderen Grund, den Code mit einer Menge zu überladenstd:: Qualifikationsmerkmalen zu - es wird nur ein Haufen visueller Geräusche. Wenn Sie jedoch nicht eine ganze Reihe von Namen aus dem stdNamespace in Ihrem Code verwenden, sehe ich auch kein Problem darin, die Direktive wegzulassen. Es ist eine Tautologie - wenn die Richtlinie nicht erforderlich ist, muss sie nicht verwendet werden.

Ebenso, wenn Sie mit ein paar using-Deklarationen (anstelle von using-Direktiven ) für bestimmte Typen in derstd Namespace , gibt es keinen Grund, warum Sie nicht nur diese spezifischen Namen in den aktuellen Namespace einfügen sollten. Aus dem gleichen Grund denke ich, dass es verrückt und ein Aufwand für die Buchhaltung wäre, 25 oder 30 Verwendungserklärungen zu haben, wenn eine einzige Verwendungsrichtlinie den Trick genauso gut machen würde.

Es ist auch gut im Auge zu behalten , dass es Zeiten , in denen Sie müssen eine using-Deklaration verwenden. Siehe Scott Meyers '"Punkt 25: Unterstützung für einen nicht werfenden Swap in Betracht ziehen" aus Effective C ++, Third Edition. Damit eine generische Funktion mit Vorlagen die 'beste' Swap-Methode für einen parametrisierten Typ verwenden kann, müssen Sie eine using-Deklaration und eine argumentabhängige Suche (auch bekannt als ADL- oder Koenig-Lookup) verwenden:

template< typename T >
void foo( T& x, T& y)
{
    using std::swap;     // makes std::swap available in this function

    // do stuff...

    swap( x, y);         // will use a T-specific swap() if it exists,
                         //  otherwise will use std::swap<T>()

    // ...
 }

Ich denke, wir sollten uns die gemeinsamen Redewendungen für verschiedene Sprachen ansehen, die Namespaces in erheblichem Maße nutzen. Beispielsweise verwenden Java und C # in großem Umfang Namespaces (wahrscheinlich mehr als C ++). Die gebräuchlichste Art und Weise, wie Namen in Namespaces in diesen Sprachen verwendet werden, besteht darin, sie massenhaft mit dem Äquivalent einer using-Direktive in den aktuellen Geltungsbereich zu bringen. Dies führt nicht zu weit verbreiteten Problemen, und die wenigen Male, bei denen es sich um ein Problem handelt, werden auf Ausnahmebasis behandelt, indem die betreffenden Namen über vollständig qualifizierte Namen oder durch Aliasing behandelt werden - genau wie dies in C ++ möglich ist.

Herb Sutter und Andrei Alexandrescu haben dies in "Punkt 59: Schreiben Sie keine Namespace-Verwendungen in eine Header-Datei oder vor einem #include" ihres Buches C ++ Coding Standards: 101 Regeln, Richtlinien und Best Practices zu sagen:

Kurz gesagt: Sie können und sollten den Namespace verwenden, indem Sie Deklarationen und Anweisungen in Ihren Implementierungsdateien nach #includeAnweisungen großzügig verwenden, und sich dabei wohl fühlen. Trotz wiederholter gegenteiliger Behauptungen ist der Namespace, der Deklarationen und Anweisungen verwendet, nicht böse und macht den Zweck von Namespaces nicht zunichte. Sie machen vielmehr Namespaces nutzbar.

Stroupstrup wird in "The C ++ Programming Language, Third Edition" häufig mit den Worten "Verschmutzen Sie nicht den globalen Namespace" zitiert. Er sagt das tatsächlich (C.14 [15]), bezieht sich aber auf Kapitel C.10.1, in dem er sagt:

Eine using-Deklaration fügt einem lokalen Bereich einen Namen hinzu. Eine using-Direktive nicht; Es macht Namen einfach in dem Bereich zugänglich, in dem sie deklariert wurden. Beispielsweise:

namespaceX {
    int i , j , k ;
}

int k ;
void f1()
{
    int i = 0 ;

    using namespaceX ; // make names from X accessible

    i++; // local i
    j++; // X::j
    k++; // error: X::k or global k ?

    ::k ++; // the global k

    X::k ++; // X’s k
}

void f2()
{
    int i = 0 ;

    using X::i ; // error: i declared twice in f2()
    using X::j ;
    using X::k ; // hides global k

    i++;
    j++; // X::j
    k++; // X::k
}

Ein lokal deklarierter Name (entweder durch eine normale Deklaration oder durch eine using-Deklaration deklariert) verbirgt nichtlokale Deklarationen mit demselben Namen, und alle illegalen Überladungen des Namens werden zum Zeitpunkt der Deklaration erkannt.

Beachten Sie den Mehrdeutigkeitsfehler für k++in f1(). Globale Namen werden nicht vor Namen aus Namespaces bevorzugt, die im globalen Bereich zugänglich gemacht werden. Dies bietet einen erheblichen Schutz vor versehentlichen Namenskonflikten und stellt - was wichtig ist - sicher, dass die Verschmutzung des globalen Namespace keine Vorteile bringt.

Wenn Bibliotheken, die viele Namen deklarieren, über using-Direktiven zugänglich gemacht werden, ist es ein wesentlicher Vorteil, dass Zusammenstöße nicht verwendeter Namen nicht als Fehler betrachtet werden.

...

Ich hoffe, dass die Verwendung globaler Namen in neuen Programmen mit Namespaces im Vergleich zu herkömmlichen C- und C ++ - Programmen radikal abnimmt. Die Regeln für Namespaces wurden speziell entwickelt, um einem "faulen" Benutzer globaler Namen keine Vorteile gegenüber jemandem zu verschaffen, der darauf achtet, den globalen Bereich nicht zu verschmutzen.

Und wie hat man den gleichen Vorteil wie ein "fauler Benutzer globaler Namen"? Durch die Nutzung der using-Direktive, die Namen in einem Namespace sicher für den aktuellen Bereich verfügbar macht.

Beachten Sie, dass es einen Unterschied gibt - Namen im stdNamespace, die einem Bereich mit der richtigen Verwendung einer using-Direktive (durch Platzieren der Direktive nach dem #includes) zur Verfügung gestellt werden , verschmutzen den globalen Namespace nicht. Es geht nur darum, diese Namen leicht verfügbar zu machen und sie weiterhin vor Zusammenstößen zu schützen.

Michael Burr
quelle
In Bezug auf Ihren letzten Punkt: Java und C # haben auch viel übersichtlichere Namespaces. Wenn alles in der BCL in System leben würde, würde "using System" genauso viel Ärger verursachen wie "using namespace std".
Jeff Hardy
Aber die Java- und C # -Programme, die ich sehe, bringen normalerweise alle von ihnen verwendeten Namespaces ein - nicht nur "System" (oder dessen Äquivalent). Anstelle einer einzigen using-Direktive, die alle verwendeten Namen enthält, gibt es 5 oder 10, die mehr oder weniger dasselbe tun. Auch "using namespace std;" wirklich so viel Ärger machen?
Michael Burr
Das Problem ist, dass std zu viele gebräuchliche Namen hat und dass das Einschließen eines Standard-Headers möglicherweise alle anderen enthält. Wir haben keine gute Kontrolle darüber, was importiert wird, es gibt zu viele Risiken. Ich weiß nicht genug über Java und C #, aber ich weiß über Ada Bescheid, das ein weitaus besseres Modulsystem als C ++ hat und bei dem das Importieren von Namen normalerweise verpönt ist. Im Allgemeinen ist es zunächst eine Frage der Namenskonvention (ich habe Leute gesehen, die sowohl Präfixe als auch Namespace verwenden, nicht zu importieren macht keinen Sinn), dann des Stils.
AProgrammer
1
Ich bin immer noch nicht davon überzeugt, dass dies ein reales Problem ist. Ich sehe, dass Verwendungsanweisungen ständig ohne schwerwiegende Nachteile verwendet werden. Andererseits habe ich kein Problem damit, sie nicht zu benutzen. Ich bevorzuge nur, dass std::Qualifikationsmerkmale den Code nicht überladen - es gibt andere Möglichkeiten, dies zu vermeiden (using-Deklarationen oder typedefs reichen normalerweise aus).
Michael Burr
1
@AProgrammer: Sie sagen, "Liste ist eine natürliche Kennung zur Identifizierung der Liste in einem Lisp-Interpreter" - aber die using namespace std;Anweisung " " hindert Sie nicht daran, Ihre natürliche Kennung zu deklarieren list"- es ist nur so, dass Sie dies nicht können, wenn Sie dies tun länger verwenden, std::listohne es zu qualifizieren. Das ist nicht anders, als wenn es keine " using namespace std;" Richtlinie gibt. Oder fehlt mir etwas?
Michael Burr
17

Verwenden Sie niemals den Namespace im globalen Bereich in einer Header-Datei. Dies kann zu Konflikten führen, und die verantwortliche Person für die Datei, in der der Konflikt auftritt, hat keine Kontrolle über die Ursache.

In der Implementierungsdatei sind die Auswahlmöglichkeiten weitaus weniger gut.

  • Wenn Sie einen using-Namespace std einfügen, werden alle Symbole aus diesen Namespaces angezeigt. Dies kann problematisch sein, da fast kein Körper alle vorhandenen Symbole kennt (daher ist es in der Praxis unmöglich, eine Politik ohne Konflikte anzuwenden), ohne von den Symbolen zu sprechen, die hinzugefügt werden. Und der C ++ - Standard erlaubt es einem Header, Symbole aus anderen Headern hinzuzufügen (der C-Standard erlaubt das nicht). In der Praxis kann es immer noch gut funktionieren, das Schreiben im kontrollierten Fall zu vereinfachen. Und wenn ein Fehler auftritt, wird er in der Datei erkannt, in der das Problem auftritt.

  • Putten mit std :: name; hat den Vorteil einer einfachen Schreibweise ohne das Risiko, unbekannte Symbole zu importieren. Die Kosten sind, dass Sie explizit alle gewünschten Symbole importieren müssen.

  • Das explizite Qualifizieren bringt ein wenig Unordnung mit sich, aber ich denke, es ist weniger schwierig, etwas zu üben.

In meinem Projekt verwende ich eine explizite Qualifikation für alle Namen, ich akzeptiere die Verwendung von std :: name, ich kämpfe gegen die Verwendung des Namespace std (wir haben einen Lisp-Interpreter, der seinen eigenen Listentyp hat und Konflikte sind daher eine sichere Sache).

Bei anderen Namespaces müssen Sie auch die verwendeten Namenskonventionen berücksichtigen. Ich kenne ein Projekt, das einen Namespace (für die Versionierung) und ein Präfix für Namen verwendet. Ein using namespace Xdann zu machen ist fast ohne Risiko und es nicht zu tun, führt zu dumm aussehendem Code PrefixNS::pfxMyFunction(...).

In einigen Fällen möchten Sie die Symbole importieren. std :: swap ist der häufigste Fall: Sie importieren std :: swap und verwenden dann swap unqualifiziert. Die argumentabhängige Suche findet einen angemessenen Austausch im Namespace des Typs, falls vorhanden, und greift auf die Standardvorlage zurück, wenn keine vorhanden ist.


Bearbeiten:

In den Kommentaren fragt sich Michael Burr, ob die Konflikte in der realen Welt auftreten. Hier ist ein echtes Live-Beispiel. Wir haben eine Erweiterungssprache mit einem Lisp-Dialekt. Unser Interpreter hat eine Include-Datei, die lisp.h enthält

typedef struct list {} list;

Wir mussten einen Code (den ich "Engine" nennen werde) integrieren und anpassen, der so aussah:

#include <list>
...
using std::list;
...
void foo(list const&) {}

Also haben wir so modifiziert:

#include <list>

#include "module.h"
...
using std::list;
...
void foo(list const&) {}

Gut. Alles funktioniert. Einige Monate später wurde "module.h" geändert, um "list.h" aufzunehmen. Die Tests bestanden. "module" wurde nicht in einer Weise geändert, die sich auf das ABI auswirkte, sodass die "engine" -Bibliothek verwendet werden konnte, ohne die Benutzer neu zu kompilieren. Integrationstests waren in Ordnung. Neues "Modul" veröffentlicht. Die nächste Kompilierung der Engine ist unterbrochen, wenn der Code nicht geändert wurde.

Ein Programmierer
quelle
1
Einer der kontrollierten Fälle, in denen ich die Verwendung eines Namespace für akzeptabel halte, ist das Veröffentlichen von Code. Die Vereinfachung erleichtert das Layout der Seite und hilft, sich auf den exponierten Punkt zu konzentrieren. Der Nachteil ist, dass es nicht wirklich eine gute Praxis zeigt, so dass ich es nicht in Büchern für Anfänger verwenden würde.
AProgrammer
1
Ich denke, die Eingabe von std :: ist ein kleiner Preis für Klarheit
paoloricardo
4
@paoloricardo: Andererseits denke ich, dass es unnötig ist, std :: überall auftauchen zu lassen.
Michael Burr
1
@ Michael: Du bezahlst dein Geld und triffst deine Wahl!
Paoloricardo
2
Vielen Dank, dass Sie sich die Zeit genommen haben, die Details des Problems hinzuzufügen, auf das Sie gestoßen sind.
Michael Burr
4

Wenn Sie kein Risiko für Namenskonflikte in Ihrem Code mit std und anderen Bibliotheken haben, können Sie Folgendes verwenden:

using namespace std;

Wenn Sie jedoch die Abhängigkeit Ihres Codes für die Dokumentation genau kennen möchten oder das Risiko von Namenskonflikten besteht, verwenden Sie die andere Methode:

using std::string;
using std::cout;

Die dritte Lösung, verwenden Sie diese Lösungen nicht und schreiben Sie std ::, bevor jede Verwendung im Code Ihnen mehr Sicherheit bringt, aber vielleicht ein wenig Schwere im Code ...

Matthieu
quelle
4

Beide

using std::string;

und

using namespace std;

Fügen Sie dem globalen Namespace einige Symbole (eines oder viele) hinzu. Das Hinzufügen von Symbolen zum globalen Namespace sollten Sie in Header-Dateien niemals tun. Sie haben keine Kontrolle darüber, wer Ihren Header enthält. Es gibt viele Header, die andere Header enthalten (und Header, die Header enthalten, die Header enthalten usw.).

In Implementierungsdateien (.cpp) liegt es an Ihnen (denken Sie nur daran, dies nach allen # include-Anweisungen zu tun ). Sie können nur Code in dieser bestimmten Datei brechen, um den Grund für Namenskonflikte einfacher zu verwalten und herauszufinden. Wenn Sie std :: (oder ein anderes Präfix, es können viele Namespaces in Ihrem Projekt vorhanden sein) vor den Einrückern bevorzugen, ist dies in Ordnung. Wenn Sie dem globalen Namespace Bezeichner hinzufügen möchten, ist dies in Ordnung. Wenn Sie einen ganzen Namespace auf Ihren Kopf bringen wollen :-), liegt es an Ihnen. Die Effekte sind zwar auf eine einzelne Kompilierungseinheit beschränkt, aber akzeptabel.

Tadeusz Kopec
quelle
3

Für mich bevorzuge ich, ::wenn möglich.

std::list<int> iList;

Ich hasse es zu schreiben:

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
    //
}

Hoffentlich würde ich mit C ++ 0x Folgendes schreiben:

for(auto i = iList.begin(); i != iList.end(); i++)
{
    //
}

Wenn der Namespace sehr lang ist,

namespace dir = boost::filesystem;

dir::directory_iterator file("e:/boost");
dir::directory_iterator end;

for( ; file != end; file++)
{
    if(dir::is_directory(*file))
        std::cout << *file << std::endl;
}
AraK
quelle
@AraK: Namespace dir = boost :: filesystem; Ich denke das ist ein Alias?
Paoloricardo
@paoloricardo: Ja, das ist es.
sbi
2
Iteratoren sollten inkrementiert werden ++i, nicht i++weil, wenn es überhaupt definiert ist, eine unnötige temporäre Kopie des Iterators erstellt wird.
Felix Dombek
2

Sie sollten sich niemals using namespace stdim Namespace-Bereich eines Headers befinden. Ich nehme an, die meisten Programmierer werden sich fragen, wann sie sehen vectoroder stringnicht std::, also denke ich, dass es nicht using namespace stdbesser ist. Dafür plädiere ich dafür, niemals zu sein using namespace std.

Wenn Sie das Gefühl haben, dass Sie müssen, fügen Sie local mit Deklarationen wie hinzu using std::vector. Aber fragen Sie sich: Was ist das wert? Eine Codezeile wird einmal (vielleicht zweimal) geschrieben, aber zehn-, hundert- oder tausendmal gelesen. Der gespeicherte Schreibaufwand beim Hinzufügen einer using-Deklaration oder Direktive ist im Vergleich zum Aufwand beim Lesen des Codes gering.

Vor diesem Hintergrund haben wir vor zehn Jahren in einem Projekt beschlossen, alle Bezeichner explizit mit ihren vollständigen Namespace-Namen zu qualifizieren. Was zunächst unangenehm schien, wurde innerhalb von zwei Wochen zur Routine. Jetzt verwendet in allen Projekten des gesamten Unternehmens niemand mehr Richtlinien oder Erklärungen. (Mit einer Ausnahme siehe unten.) Wenn ich mir den Code (mehrere MLoC) nach zehn Jahren anschaue, habe ich das Gefühl, dass wir die richtige Entscheidung getroffen haben.

Ich habe festgestellt, dass diejenigen, die sich dem Verbot widersetzen, es usingnormalerweise nicht für ein Projekt ausprobiert haben. Diejenigen, die es versucht haben, finden es oft besser, als nach sehr kurzer Zeit Richtlinien / Erklärungen zu verwenden.

Hinweis: Die einzige Ausnahme ist using std::swapdie, die erforderlich ist (insbesondere im generischen Code), um Überladungen aufzunehmen swap(), die nicht in den stdNamespace eingefügt werden können (da wir keine Überladungen von stdFunktionen in diesen Namespace einfügen dürfen).

sbi
quelle
3
Eine Spezialisierung von std :: swap wäre eine vollständige Spezialisierung - Sie können Funktionsvorlagen nicht teilweise spezialisieren. Jedes Programm ist erlaubt, teilweise jede Standard - Bibliothek - Vorlage zu spezialisieren , so lange , dass die Spezialisierung ist abhängig von einem benutzerdefinierten Typ.
CB Bailey
@ Charles: Ja, du hast Recht, natürlich gibt es kein FTPS. Und ich kann mich auf Vorlagen spezialisierenstd , aber nicht überladen. Entschuldigung für diesen Brainfart. Ich werde den Beitrag korrigieren.
sbi
2
Ich glaube nicht, dass die Absicht der using namespaceRichtlinie darin bestand, das Tippen zu machen . Vielmehr sollte es das Lesen erleichtern, da dieser Code, wie Sie sagen, Dutzende, Hunderte oder Tausende Male gelesen werden muss. Und für einige Leute liest es sich viel einfacher mit weniger std::Unordnung. Aber das hängt wahrscheinlich von der persönlichen Wahrnehmungsfähigkeit ab; Einige Leute filtern std::weg oder brauchen es sogar zur Führung (wie Serifen), andere stolpern darauf und fühlen sich wie auf einer holprigen Straße.
Lumi
1
@sbi: Nein, das ist nicht objektiv. Es hängt davon ab, ob Sie der Meinung sind, dass std :: hilfreich ist oder nicht. Mehr Unordnung -> weniger Klarheit.
Joshua Richardson
2

Namespaces enthalten Code, um Verwirrung und Verschmutzung der Funktionssignaturen zu vermeiden .

Hier ist eine vollständige und dokumentierte Demo der richtigen Verwendung von Namespaces :

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see /programming/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

Ausgabe:

Our log: 42
Standard log: 1.43508
Cees Timmerman
quelle
1

using namespace stdImportiert den Inhalt des stdNamespace in den aktuellen. Der Vorteil ist also, dass Sie nicht std::vor allen Funktionen dieses Namespace tippen müssen . Es kann jedoch vorkommen, dass Sie unterschiedliche Namespaces mit gleichnamigen Funktionen haben. Daher können Sie damit enden, nicht den gewünschten anzurufen.

Wenn Sie manuell angeben, in welche Dateien Sie importieren möchten, wird dies stdverhindert. Dies kann jedoch zu einer langen Liste von Verwendungszwecken am Anfang Ihrer Datei führen, die einige Entwickler als hässlich empfinden.

Persönlich bevorzuge ich es, den Namespace jedes Mal anzugeben, wenn ich eine Funktion verwende, außer wenn der Namespace zu lang ist. In diesem Fall setze ich einen am Anfang der Datei.

BEARBEITEN: Wie in einer anderen Antwort angegeben, sollten Sie niemals eine using namespacein eine Header-Datei einfügen, da diese an alle Dateien einschließlich dieses Headers weitergegeben wird und daher zu unerwünschtem Verhalten führen kann.

EDIT2: korrigierte meine Antwort dank Charles Kommentar.

Wookai
quelle
2
using namespace std;Importiert den Inhalt des stdNamespace in den globalen Namespace. Der Standard-Namespace wird nicht geändert. Wenn Sie etwas im globalen Namespace nach a definieren, using namespace stdwird es nicht auf magische Weise in den stdNamespace eingefügt.
CB Bailey
Entschuldigung, das habe ich nicht gemeint. Vielen Dank für den Hinweis, ich werde meine Antwort korrigieren.
Wookai
1
Leute: Danke für die Antworten. Es scheint im Allgemeinen sicherer zu sein, "using namespace std" nicht zu verwenden und mögliche Mehrdeutigkeiten zu vermeiden. Alles in allem spricht mich die Verwendung von 'std :: xxx' mehr an, als eine Liste der verschiedenen Funktionen am Anfang der Quelldatei zu deklarieren, da sie eindeutig die Absicht eines Menschen qualifiziert.
Paoloricardo
1
Zitat (außer wenn der Namespace zu lang ist). Sie können Namespace-Aliasing verwenden, um dort zu helfen. 'Namespace Rv1 = Thor :: XML :: XPath :: Rules :: Light :: Version1;' Beachten Sie Aliase und verwenden Sie beide Regeln.
Martin York
0

Ähnlich wie in Java, wo Sie entweder java.util. * Einschließen oder einfach jede Klasse einzeln auswählen können, hängt dies vom Stil ab. Beachten Sie, dass Sie using namespace stdam Anfang Ihrer Datei / Ihres weiten Bereichs keinen möchten, da Sie den Namespace verschmutzen und möglicherweise Konflikte verursachen, wodurch der Punkt der Namespaces zunichte gemacht wird. Wenn Sie jedoch eine Funktion haben, die viel STL verwendet, wird der Code so durcheinander gebracht, dass die Logik ein Durcheinander von Präfixsyntax enthält, und Sie sollten wahrscheinlich in Betracht ziehen, entweder using namespace std(bei Verwendung verschiedener Klassen) oder einzelne usings (bei Verwendung einiger weniger) zu verwenden Klassen oft).

Sam Brightman
quelle
0

Diese Diskussion wird so lange lebendig sein, wie die IDE, mit der Sie arbeiten, nicht flexibel genug ist, um die genauen Informationen anzuzeigen oder auszublenden, die Sie benötigen.

Das liegt daran, dass es von der jeweiligen Aufgabe abhängt, wie Ihr Code aussehen soll.

Beim Erstellen meines Quellcodes möchte ich lieber genau sehen, welche Klasse ich verwende: Ist es std::stringoder die BuzFlox::Obs::stringKlasse?

Beim Entwerfen des Kontrollflusses interessieren mich nicht einmal die Arten der Variablen, aber ich möchte mich auf if's while' und continue's ' und 's konzentrieren.

Das ist also mein Rat:

Wählen Sie abhängig von der Zielgruppe Ihres Codes und der Leistung Ihrer Tools die Art und Weise, die entweder am einfachsten zu lesen ist oder die meisten Informationen liefert.

xtofl
quelle
0

Es gibt verschiedene Möglichkeiten, dies zu beheben.

Erstens: Verwenden Sie wie das, was Sie getan haben.

Zweitens: namespace S = std;Reduzieren Sie 2 Zeichen.

Drittens: verwenden static.

Viertens: Verwenden Sie keine Namen, die stdverwenden.


quelle
-1

Was sind die Vor- und Nachteile von jedem

Der einzige Grund, auf std :: zu verzichten, besteht darin, dass Sie theoretisch alle STL-Funktionen selbst neu implementieren können. Dann könnten Ihre Funktionen von std :: vector auf my :: vector umgestellt werden, ohne den Code zu ändern.

Martin Beckett
quelle
Namespaces sind nicht wirklich so konzipiert, dass Namen durch andere, aber gleichwertige Funktionen ersetzt werden können. Sie sollen unbeabsichtigte Namenskonflikte verhindern.
Michael Burr
Ja, die einzige Rechtfertigung für die 'using'-Direktive, die dies unterbricht, besteht darin, dass Sie Funktionen in einen neuen Namespace wechseln können.
Martin Beckett
Ich denke, Sie würden eine Menge Programmierer finden, die sich darüber beschweren, was für ein Schmerz in den Arsch-Namespaces ist und sie aus dem Fenster werfen wollen, wenn es keine using-Direktive gäbe. Soweit ich weiß, hat jede Sprache, die Namespaces verwendet, etwas Ähnliches wie eine using-Direktive, um sie aus dem Weg zu räumen, wenn Sie sie aus dem Weg haben möchten. Wenn die Richtlinien nutzlos sind, warum existieren sie überall?
Michael Burr
Ich denke, das "Verwenden" sollte es Ihnen ermöglichen, zu alternativen Implementierungen zu wechseln, anstatt die Eingabe von 3 Buchstaben zu speichern. Ich benutze gerne "std :: Foo", weil es dem Programmierer als Vertrag dient, dass ich das normale Foo verwende und sie nicht überprüfen müssen. Ich bin damit einverstanden, dass ich nicht "com.microsoft.visual-studio.standard-library.numbers.int foo" eingeben muss, einige der Iterator-Deklarationen in der STL werden so. Python macht einen guten Job, indem es Ihnen ermöglicht, dekorierte oder nicht dekorierte Funktionssätze aus Modulen abzurufen.
Martin Beckett
-1

Warum nicht zum Beispiel

typedef std::vector<int> ints_t;
ints_t ints1;
....
ints_t ints2;

statt der unhandlichen

std::vector<int> ints1;
...
std::vector<int> ints2;

Ich finde das viel lesbarer und es ist mein Standard für die Codierung.

Sie können es sogar verwenden, um einige semantische Informationen für den Leser einzuschließen. Betrachten Sie beispielsweise die Funktionsprototypen

void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);

Welches ist der Rückgabewert?

Wie wäre es stattdessen

typedef std::vector<unsigned int> values_t;
typedef std::vector<unsigned int> histogram_t;
...
void getHistogram(values_t&, histogram_t&); 
ldog
quelle