Warum wird "Namespace std verwenden"; als schlechte Praxis angesehen?


2640

Ich habe von anderen gesagt , dass das Schreiben using namespace std;in Code falsch ist, und dass ich verwenden sollte std::coutund std::cinstattdessen direkt.

Warum wird dies using namespace std;als schlechte Praxis angesehen? Ist es ineffizient oder besteht die Gefahr, dass mehrdeutige Variablen deklariert werden (Variablen, die denselben Namen wie eine Funktion im stdNamespace haben)? Beeinträchtigt es die Leistung?


512
Vergessen Sie nicht, dass Sie Folgendes tun können: "using std :: cout;" Dies bedeutet, dass Sie nicht std :: cout eingeben müssen, sondern nicht den gesamten std-Namespace gleichzeitig einbringen müssen.
Bill

2
@ ein bezahlter Nerd google-styleguide.googlecode.com/svn/trunk/… Link funktioniert nicht mehr. Sieht aus wie neuer Link ist google.github.io/styleguide/cppguide.html#Other_C++_Features
MCG

64
Es ist besonders schlecht, 'using namespace std' im Dateibereich in Header-Dateien zu verwenden. Die Verwendung in Quelldateien (* .cpp) im Dateibereich ist schließlich nicht ganz so schlecht, da die Wirkung auf eine einzelne Übersetzungseinheit beschränkt ist. Noch weniger problematisch ist die Verwendung innerhalb von Funktionen oder Klassen, da seine Wirkung auf die Funktion oder den Klassenbereich beschränkt ist.
sh

5
Ich würde entmutigen Richtlinie zu verwenden , verwenden aber für bestimmte Namensräume wie std::literals::chrono_literals, Poco::Data:Keywords, Poco::Unitsund Sachen , die mit Literalen oder Lesbarkeit Tricks beschäftigen. Wann immer es in Header- oder Implementierungsdateien ist. Es mag in einem Funktionsumfang in Ordnung sein, aber abgesehen von Literalen und anderen Dingen ist es nicht nützlich.
Ludovic Zenohate Lagouardette

7
@ Jon: Es hat nichts mit dem Namespace std zu tun. Mein Schwerpunkt sollte auf "im Dateibereich in Header-Dateien" liegen. Um es als Hinweis zu formulieren: Verwenden Sie nicht "using namespace" (std oder andere) im Dateibereich in Header-Dateien. Es ist in Ordnung, es in Implementierungsdateien zu verwenden. Entschuldigung für die Mehrdeutigkeit.
sh-

Antworten:


2230

Dies hängt überhaupt nicht mit der Leistung zusammen. Beachten Sie jedoch Folgendes: Sie verwenden zwei Bibliotheken mit den Namen Foo und Bar:

using namespace foo;
using namespace bar;

Alles funktioniert gut und Sie können problemlos Blah()von Foo und Quux()Bar anrufen . Aber eines Tages aktualisieren Sie auf eine neue Version von Foo 2.0, die jetzt eine Funktion namens bietet Quux(). Jetzt haben Sie einen Konflikt: Sowohl Foo 2.0 als auch Bar werden Quux()in Ihren globalen Namespace importiert . Die Behebung dieses Problems erfordert einige Anstrengungen, insbesondere wenn die Funktionsparameter übereinstimmen.

Wenn Sie foo::Blah()und verwendet hätten bar::Quux(), foo::Quux()wäre die Einführung von kein Ereignis gewesen.


435
Ich habe Pythons "import big_honkin_name as bhn" immer gemocht, sodass Sie dann einfach "bhn.something" anstelle von "big_honkin_name.something" verwenden können - was die Eingabe wirklich einschränkt. Hat C ++ so etwas?
Paxdiablo

764
@Pax Namespace io = boost :: filesystem;
AraK

152
Ich denke, es ist übertrieben zu sagen, dass es "einige Anstrengungen zur Behebung" sind. Sie werden keine Instanzen des neuen foo :: Quux haben, also disambiguieren Sie einfach alle Ihre aktuellen Verwendungen mit bar :: Quux.
MattyT

289
Würde eine vernünftige Person eine Bibliothek mit Typen erstellen, deren unqualifizierter Name mit den Standardtypen kollidiert?
Erikkallen

94
@ TomA: Das Problem dabei #defineist, dass es sich nicht auf Namespaces beschränkt, sondern über die gesamte Codebasis trampelt. Ein Namespace-Alias ​​ist das, was Sie wollen.
sbi

1391

Ich stimme allem zu, was Greg geschrieben hat , aber ich möchte hinzufügen: Es kann noch schlimmer werden, als Greg gesagt hat!

Library Foo 2.0 könnte eine Funktion einführen Quux(), die für einige Ihrer Aufrufe eindeutig besser passt Quux()als der bar::Quux()Code, den Sie seit Jahren aufgerufen haben. Dann wird Ihr Code immer noch kompiliert , aber er ruft stillschweigend die falsche Funktion auf und macht Gott-weiß-was. Das ist ungefähr so ​​schlimm, wie es nur geht.

Beachten Sie, dass der stdNamespace - Tonnen - Kennungen hat, von denen viele sehr gewöhnlichsten (denken list, sort, string, iteratoretc.) , die sehr wahrscheinlich in anderen Code erscheinen, zu.

Wenn Sie dies für unwahrscheinlich halten: Hier auf Stack Overflow wurde eine Frage gestellt, bei der genau std::ein halbes Jahr, nachdem ich diese Antwort gegeben habe, ziemlich genau dies passiert ist (falsche Funktion wird aufgrund des ausgelassenen Präfixes aufgerufen ). Hier ist ein weiteres, neueres Beispiel für eine solche Frage. Das ist also ein echtes Problem.


Hier noch ein Datenpunkt: Vor vielen, vielen Jahren fand ich es auch ärgerlich, alles aus der Standardbibliothek voranstellen zu müssen std::. Dann habe ich in einem Projekt gearbeitet, in dem zu Beginn entschieden wurde, dass sowohl usingDirektiven als auch Deklarationen mit Ausnahme von Funktionsbereichen verboten sind. Erraten Sie, was? Die meisten von uns brauchten sehr wenige Wochen, um sich an das Schreiben des Präfixes zu gewöhnen, und nach einigen weiteren Wochen waren sich die meisten sogar einig, dass der Code dadurch besser lesbar wurde . Dafür gibt es einen Grund: Ob Sie kürzere oder längere Prosa mögen, ist subjektiv, aber die Präfixe verleihen dem Code objektiv Klarheit. Nicht nur der Compiler, sondern auch Sie können leichter erkennen, auf welchen Bezeichner verwiesen wird.

In einem Jahrzehnt wuchs dieses Projekt auf mehrere Millionen Codezeilen. Da diese Diskussionen immer wieder auftauchen, war ich einmal gespannt, wie oft der (erlaubte) Funktionsumfang usingtatsächlich im Projekt verwendet wurde. Ich suchte nach den Quellen dafür und fand nur ein oder zwei Dutzend Stellen, an denen es verwendet wurde. Für mich bedeutet dies, dass Entwickler nach dem Versuch nicht std::schmerzhaft genug sind, um Direktiven auch nur einmal alle 100 kLoC zu verwenden, selbst wenn sie verwendet werden durften.


Fazit: Das explizite Präfixieren von allem schadet nicht, ist sehr gewöhnungsbedürftig und hat objektive Vorteile. Insbesondere erleichtert dies die Interpretation des Codes durch den Compiler und durch menschliche Leser - und dies sollte wahrscheinlich das Hauptziel beim Schreiben von Code sein.


140
Dies beeinträchtigt die Codedichte, die Sie in eine einzelne Zeile packen können, erheblich. Am Ende schreiben Sie Ihren Code auf sehr langwierige Weise. Dies verringert die Lesbarkeit. Persönlich denke ich, dass kürzerer (aber nicht zu kurzer) Code tendenziell besser lesbar ist (da weniger Dinge zu lesen und weniger Dinge abzulenken sind).
Lie Ryan

91
Vermutlich haben Sie die alten Tage verpasst, bevor C ++ eine Standardklasse hatte string, und anscheinend hatte jede Bibliothek ihre eigene. Sagen Sie was: Wir werden unseren Code weiter schreiben std::, und Sie können unseren Code durchlaufen, grep -v std:: | vimwenn Sie ihn durchsuchen. Oder Sie können Ihrem Editor beibringen, dass std::es sich um ein Schlüsselwort handelt, das genauso wie die Hintergrundfarbe gefärbt werden soll. Was auch immer funktioniert.
Mike DeSimone

79
Ich denke nicht, dass std::es überhaupt schädlich ist. Es enthält sehr wichtige Informationen (nämlich "was auch immer danach kommt, ist Teil der Standardbibliothek", und es ist immer noch ein ziemlich kurzes und kompaktes Präfix. Meistens ist es überhaupt kein Problem. Manchmal haben Sie ein paar Codezeilen wo Sie bestimmen Symbole in der verweisen müssen stdvielen Namensraum, und dann ein using. das Problem schön Aussage in dieser besonderen Rahmen löst aber im allgemeinen Fall ist es nicht Lärm, vermittelt es wertvolle Informationen zusätzlich zu entfernen Zweideutigkeiten.
JALF

146
Wann immer ich sehe std:: , weiß ich, dass es von kommen wird, std::ohne darüber nachdenken zu müssen. Wenn ich stringoder listoder mapalleine sehe, frage ich mich ein bisschen.
Mateen Ulhaq

67
@LieRyan Dann viel Glück beim Schreiben einer Geometriebibliothek, ohne jemals etwas zu benennen vector, transformoder distance. Und das sind nur Beispiele für die vielen, sehr gebräuchlichen Namen, die in der Standardbibliothek verwendet werden. Es ist eher kontraproduktiv, sie nicht aus Angst oder aus einer voreingenommenen Meinung über die Namespace-Funktion zu verwenden, die ein wesentlicher Bestandteil von C ++ ist.
Christian Rau

420

Das Problem beim Einfügen using namespaceder Header-Dateien Ihrer Klassen besteht darin, dass jeder, der Ihre Klassen verwenden möchte (indem er Ihre Header-Dateien einbezieht), auch diese anderen Namespaces "verwendet" (dh alles darin sieht).

Sie können jedoch auch eine using-Anweisung in Ihre (privaten) * .cpp-Dateien einfügen.


Beachten Sie, dass einige Leute mit meinem Sprichwort "Fühlen Sie sich frei" nicht einverstanden sind - denn obwohl a using Aussage in einer CPP-Datei besser ist als in einem Header (weil sie keine Auswirkungen auf Personen hat, die Ihre Header-Datei enthalten), denken sie, dass dies immer noch nicht der Fall ist gut (weil es je nach Code die Wartung der Klasse schwieriger machen könnte). Dieser C ++ Super-FAQ-Eintrag sagt:

Die using-Direktive existiert für älteren C ++ - Code und um den Übergang zu Namespaces zu erleichtern. Sie sollten sie jedoch wahrscheinlich nicht regelmäßig verwenden, zumindest nicht in Ihrem neuen C ++ - Code.

Die FAQ schlägt zwei Alternativen vor:

  • Eine using-Erklärung:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
  • Geben Sie einfach std :: ein

    std::cout << "Values:";

1
Natürlich sollten Sie auch niemals den Status des globalen cout annehmen, damit nicht jemand std: cout << std :: hex hat und danach std :: restore_cout_state nicht mehr konnte. Aber das ist ein ganz anderer Fatberg.
Móż

233

Ich bin kürzlich auf eine Beschwerde über Visual Studio 2010 gestoßen . Es stellte sich heraus, dass so ziemlich alle Quelldateien diese beiden Zeilen hatten:

using namespace std;
using namespace boost;

Viel Boost Funktionen werden in den C ++ 0x-Standard aufgenommen, und Visual Studio 2010 verfügt über viele C ++ 0x-Funktionen, sodass diese Programme plötzlich nicht mehr kompiliert wurden.

Vermeiden using namespace X;ist daher eine Form der Zukunftssicherheit, um sicherzustellen, dass eine Änderung der verwendeten Bibliotheken und / oder Header-Dateien ein Programm nicht beschädigt.


14
Diese. Boost und Standard haben viele Überlappungen - insbesondere seit C ++ 11.
Einpoklum

1
Ich habe das einmal gemacht und auf die harte Tour eine Lektion gelernt. Jetzt verwende ich nie usingaußerhalb einer Funktionsdefinition und using namespaceüberhaupt nicht mehr.
Ferruccio

210

Kurzversion: Verwenden Sie keine globalen usingDeklarationen oder Anweisungen in Header-Dateien. Fühlen Sie sich frei, sie in Implementierungsdateien zu verwenden. Hier ist, was Herb Sutter und Andrei Alexandrescu zu diesem Thema in C ++ Coding Standards zu sagen haben (Fettdruck für die Betonung liegt bei mir):

Zusammenfassung

Namespace-Verwendungen dienen Ihrer Bequemlichkeit und nicht anderen, die Sie anderen zufügen möchten: Schreiben Sie niemals eine using-Deklaration oder eine using-Direktive vor einer # include-Direktive.

Folgerung: Schreiben Sie in Header-Dateien keine Namespace-Ebene mit Direktiven oder Deklarationen. Stattdessen qualifizieren Sie alle Namen explizit für den Namespace. (Die zweite Regel folgt aus der ersten, da Header nie wissen können, welche anderen Header #includes nach ihnen erscheinen könnten.)

Diskussion

Kurz gesagt: Sie können und sollten den Namespace verwenden, indem Sie Deklarationen und Anweisungen in Ihren Implementierungsdateien nach # include-Anweisungen 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 .


4
Nur noch eine Meinung des Programmierers, aber obwohl ich der Aussage, dass das Wort usingniemals in einem Header erscheinen sollte, zu 100% zustimme , bin ich nicht so überzeugt von der kostenlosen Lizenz, using namespace xyz;irgendwo in Ihrem Code zu platzieren, besonders wenn dies der Fall xyziststd . Ich verwende das using std::vector;Formular, da dadurch nur ein einzelnes Element aus dem Namespace in den pseudo-globalen Bereich gezogen wird, was zu einem weitaus geringeren Kollisionsrisiko führt.
dgnuff

2
@Lightness Races in Orbit Sie haben natürlich ein Recht auf Ihre Meinung. Wäre hilfreicher gewesen, wenn versucht worden wäre zu erklären, warum Sie den Ratschlägen in dieser Antwort nicht zustimmen. Wäre es besonders interessant zu verstehen, wozu Namespaces gut sind, wenn es schlecht ist, sie zu verwenden? Warum nicht einfach Dinge benennen, die std_cout anstelle von std :: cout sind? Die Entwickler von C ++ / Namespace müssen eine Idee gehabt haben, als sie sich die Mühe gemacht haben, sie zu erstellen.
Nyholku

1
@nyholku: Keine Notwendigkeit - die meisten anderen Antworten geben die gleichen Gründe an, die ich hätte. Bitte zögern Sie auch nicht, das ":)" zu beachten, das ich meinem Kommentar beigefügt habe! Und dass ich nicht gesagt habe, dass Namespaces schlecht sind.
Leichtigkeitsrennen im Orbit

Ja, das ist mir aufgefallen :) aber IMO ist die Mehrheit der Antworten (die gegen diesen weisen Rat verstoßen) falsch (nicht, dass ich Statistiken erstellt habe, was jetzt die Mehrheit ist). Wenn Sie damit einverstanden sind, dass der Namespace "nicht schlecht" ist, können Sie sagen, wo Sie ihn für angemessen halten, wenn Sie mit dieser Antwort nicht einverstanden sind?
Nyholku

Ich kann nicht anders, als das Gefühl zu haben, dass using namespacees böse ist, wie gotoes böse ist. Beide haben gültige Verwendungen, aber 999 von 1000 werden sie falsch verwendet. Also, ja, mit using namespacein der Quelle werden Sie den Namespace anderer Includes nicht verschmutzen, ordentlich. Aber es schützt dich immer noch nicht vor dem "Spaß" , der entsteht, wenn using namespace Foo+ using namespace Bardu anrufst (implizites Foo: :) baz(xyz)und plötzlich der Code bricht (ohne verwandte Änderungen), nur weil er Bar::baz()irgendwo hinzugefügt wurde, was einfach besser ist Match (und wird jetzt stattdessen aufgerufen)
CharonX

122

Man sollte die usingDirektive nicht im globalen Bereich verwenden, insbesondere in Headern. Es gibt jedoch Situationen, in denen dies auch in einer Header-Datei angemessen ist:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; // No problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

Dies ist besser als die explizite Qualifizierung ( std::sin, std::cos...), da sie kürzer ist und mit benutzerdefinierten Gleitkommatypen (über argumentabhängige Suche (ADL)) arbeiten kann.


9
Es tut mir leid, aber ich bin damit überhaupt nicht einverstanden.
Billy ONeal

4
@ Billy: Es gibt keine andere Möglichkeit, das Aufrufen von userlib :: cos (userlib :: superint) zu unterstützen. Jede Funktion hat eine Verwendung.
Zan Lynx

17
@ Zan: Natürlich gibt es. using std::cos;, using std::sinObwohl usw. Das Problem ist , dass jeder gut gestaltet userlibwird sie haben sinund cosin ihrem eigenen Namensraum als auch, so die wirklich helfen Ihnen nicht. (Es sei denn, es gibt eine using namespace userlibvor dieser Vorlage und das ist genauso schlecht wie using namespace std- und der Umfang dort ist nicht begrenzt.) Außerdem ist die einzige Funktion wie diese, die mir jemals passiert swap, und in solchen Fällen würde ich empfehlen, nur eine Vorlage zu erstellen Spezialisierung std::swapund Vermeidung des gesamten Problems.
Billy ONeal

11
@ BillyONeal: template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)(Es gibt keine partielle Spezialisierung für Funktionsvorlagen (FTPS), daher müssen Sie manchmal stattdessen auf Überlastung zurückgreifen.
sbi

38
@BillyONeal: Ihr Kommentar (7-mal positiv bewertet!) Ist falsch - die von Ihnen beschriebene Situation ist genau das , wofür ADL entwickelt wurde. Kurz gesagt, wenn xein oder mehrere "zugeordnete Namespaces" vorhanden sind (z. B. wenn er in definiert wurde namespace userlib), wird jeder Funktionsaufruf, der so aussieht cos(x), zusätzlich in diesen Namespaces angezeigt - ohne dass dies using namespace userlib;zuvor erforderlich ist. Zan Lynx hat recht (und die Suche nach C ++ - Namen ist byzantinisch ...)
j_random_hacker

97

Verwenden Sie es nicht global

Es wird nur dann als "schlecht" angesehen, wenn es global verwendet wird . Weil:

  • Sie überladen den Namespace, in dem Sie programmieren.
  • Leser werden Schwierigkeiten haben zu erkennen, woher eine bestimmte Kennung kommt, wenn Sie viele verwenden using namespace xyz.
  • Was auch immer für andere Leser Ihres Quellcodes gilt, gilt umso mehr für den häufigsten Leser: Sie selbst. Komm in ein oder zwei Jahren zurück und schau mal ...
  • Wenn Sie nur darüber sprechen, sind using namespace stdSie sich möglicherweise nicht all der Dinge bewusst, die Sie greifen - und wenn Sie eine weitere hinzufügen #includeoder zu einer neuen C ++ - Version wechseln, können Namenskonflikte auftreten, die Ihnen nicht bekannt waren.

Sie können es lokal verwenden

Gehen Sie voran und verwenden Sie es lokal (fast) frei. Dies verhindert natürlich, dass Sie sich wiederholenstd:: - und Wiederholung ist auch schlecht.

Eine Redewendung für die lokale Verwendung

In C ++ 03 gab es eine Redewendung - Boilerplate-Code - zum Implementieren einer swapFunktion für Ihre Klassen. Es wurde vorgeschlagen, dass Sie tatsächlich ein lokales verwenden using namespace std- oder zumindest using std::swap:

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

Dies macht die folgende Magie:

  • Der Compiler wählt das std::swapfür value_, dh void std::swap(int, int).
  • Wenn Sie eine Überladung void swap(Child&, Child&)implementiert haben, wählt der Compiler diese aus.
  • Wenn Sie diese Überlastung nicht haben, wird der Compiler diese verwenden void std::swap(Child&,Child&)und versuchen, diese am besten auszutauschen.

Mit C ++ 11 gibt es keinen Grund mehr, dieses Muster zu verwenden. Die Implementierung von std::swapwurde geändert, um eine mögliche Überlastung zu finden und auszuwählen.


5
"Die Implementierung von std :: swap wurde geändert, um eine mögliche Überlastung zu finden und diese auszuwählen." - Was? Bist du dir da sicher? Es ist zwar richtig, dass das Bereitstellen einer benutzerdefinierten Funktion swapin C ++ 11 nicht mehr so ​​wichtig ist, da die std::swapselbst flexibler ist (verwendet die Bewegungssemantik). Aber std::swapautomatisch Ihren eigenen Swap zu wählen, das ist absolut neu für mich (und ich glaube es nicht wirklich).
Christian Rau

@ChristianRau Ich denke schon, ja. Ich habe das irgendwo auf SO gelesen. Wir können Howard immer fragen , er sollte es wissen. Ich grabe und grabe jetzt ...
Towi

14
Selbst im Swap-Fall ist die klarere (und glücklicherweise häufigere) Redewendung eher das Schreiben using std::swap;als das Schreiben using namespace std;. Die spezifischere Sprache hat weniger Nebenwirkungen und macht den Code daher wartbarer.
Adrian McCarthy

11
Der letzte Satz ist falsch. In C ++ 11 wurde der Std Swap Two Step offiziell als die richtige Art des Anrufs gesegnet swap, und verschiedene andere Stellen im Standard wurden geändert, um zu sagen, dass sie so anrufen swap(NB, wie oben angegeben, using std::swapist der richtige Weg, nicht using namespace std). Aber std::swapselbst wurde nachdrücklich nicht verändert, um andere zu finden swapund zu nutzen. Wenn es std::swapangerufen wird, std::swapwird es verwendet.
Jonathan Wakely

3
Es kann jedoch sinnvoller sein, nur using std::swaplokal einzugeben, um den lokalen Namespace zu verkleinern und gleichzeitig selbstdokumentierenden Code zu erstellen. Sie sind selten jemals an dem gesamten Standard-Namespace interessiert, wählen Sie also einfach die Teile aus, an denen Sie interessiert sind.
Lundin

79

Wenn Sie die richtigen Header - Dateien importieren Sie plötzlich Namen wie hex, left, plusoder countin Ihrem globalen Rahmen. Dies kann überraschend sein, wenn Sie nicht wissen, dass std::diese Namen enthalten sind. Wenn Sie auch versuchen, diese Namen lokal zu verwenden, kann dies zu Verwirrung führen.

Wenn sich alle Standardmaterialien in einem eigenen Namespace befinden, müssen Sie sich keine Gedanken über Namenskollisionen mit Ihrem Code oder anderen Bibliotheken machen.


12
+1 ganz zu schweigen distance. Trotzdem bevorzuge ich nicht qualifizierte Namen, wo immer dies praktisch möglich ist, da dies die Lesbarkeit für mich erhöht. Außerdem denke ich, dass die Tatsache, dass wir Dinge in der mündlichen Rede normalerweise nicht qualifizieren und bereit sind, Zeit damit zu verbringen, mögliche Unklarheiten zu lösen, bedeutet, dass es wertvoll ist, verstehen zu können, worüber man ohne Qualifikationen spricht, und auf die Quelle angewendet zu werden Code, der bedeutet, dass er so strukturiert ist, dass auch ohne Qualifikation klar ist, worum es geht.
Prost und hth. - Alf

Um fair zu sein, haben Sie die meisten davon nicht, wenn Sie nicht einschließen <iomanip>. Trotzdem guter Punkt.
Einpoklum

48

Ein weiterer Grund ist die Überraschung.

Wenn ich sehe cout << blah, anstatt zu std::cout << blahdenken: Was ist das cout? Ist es die normale cout? Ist es etwas Besonderes?


25
Ist das ein Witz? Ich kann es wirklich nicht sagen. Wenn nicht, würde ich persönlich annehmen, dass es das normale "Cout" ist, es sei denn, Sie vertrauen dem Code nicht, da dies sonst ein über den MAJOR hinausgehender Codegeruch wäre, IMO. ... Und wenn Sie dem Code nicht vertrauen, warum verwenden Sie ihn dann überhaupt? Beachten Sie, dass ich nicht "VERTRAUEN SIE ALLES !!" sage. Dies scheint aber auch etwas weit hergeholt zu sein, wenn Sie sich beispielsweise mit einer bekannten Bibliothek von GitHub oder so beschäftigen.
Brent Rittenhouse

28
@BrentRittenhouse coutist ein schlechtes Beispiel, weil jeder es erkennt. Aber stellen Sie sich futurein einer Finanz-App vor. Ist es ein Vertrag, etwas zu einem bestimmten Datum zu kaufen oder zu verkaufen? Nein, ist es nicht. Wenn der Code besagt, dass std::futureSie nicht so leicht verwirrt sind.
James Hollis

2
@BrentRittenhouse vielleicht ein kleines schlechtes Beispiel, es gibt mindestens vier verschiedene Bibliotheken, die cout haben. Kann sein "ist es Standardbibliothek? Libstdc ++? Stl? Etwas anderes?" Und nein, nicht jeder kennt std :: cout, zumindest von Natur aus, 6 von 7 neuen Arbeitern, die wir erhalten, nicht. Weil die Lehrpläne diese nicht in der Bildung verwenden. Ich muss printfs verjagen. Oder debugs () - von Qt.
Swift - Friday Pie

1
"Ja wirklich?" Es ist so ziemlich das erste Beispiel des ersten Kapitels von sooo vielen Büchern über C ++, wenn überhaupt, ist es (mit Verwendung des Einfügeoperators ) das einzige C ++, das einige neue Körper kennen.
McKenzm

@ McKenzm Ich könnte es in ein Buch oder Vorlesungsnotizen setzen, um Unordnung zu reduzieren, aber nicht in Code
Martin Beckett

45

Erfahrene Programmierer verwenden alles, was ihre Probleme löst, und vermeiden alles, was neue Probleme verursacht. Aus genau diesem Grund vermeiden sie Verwendungsanweisungen auf Header-Dateiebene.

Erfahrene Programmierer versuchen auch, die vollständige Qualifizierung von Namen in ihren Quelldateien zu vermeiden. Ein kleiner Grund dafür ist, dass es nicht elegant ist, mehr Code zu schreiben, wenn weniger Code ausreicht, es sei denn, es gibt gute Gründe . Ein Hauptgrund dafür ist das Deaktivieren der argumentabhängigen Suche (ADL).

Was sind diese guten Gründe ? Manchmal möchten Programmierer ADL explizit deaktivieren, manchmal möchten sie eindeutig unterscheiden.

Folgendes ist also in Ordnung:

  1. Using-Direktiven und using-Deklarationen auf Funktionsebene in den Implementierungen von Funktionen
  2. Verwendungsdeklarationen auf Quelldateiebene in Quelldateien
  3. (Manchmal) Verwendungsanweisungen auf Quelldateiebene

43

Ich bin damit einverstanden, dass es nicht global verwendet werden sollte, aber es ist nicht so böse, es lokal zu verwenden, wie in a namespace. Hier ist ein Beispiel aus "The C ++ Programming Language" :

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

In diesem Beispiel haben wir mögliche Namenskonflikte und Unklarheiten behoben, die sich aus ihrer Zusammensetzung ergeben.

Dort explizit deklarierte Namen (einschließlich Namen, die durch using-Deklarationen wie deklariert wurden His_lib::String) haben Vorrang vor Namen, die durch eine using-Direktive ( using namespace Her_lib) in einem anderen Bereich zugänglich gemacht werden .


29

Ich halte es auch für eine schlechte Praxis. Warum? Nur eines Tages dachte ich, dass die Funktion eines Namespace darin besteht, Dinge zu teilen, also sollte ich es nicht verderben, alles in eine globale Tasche zu werfen.

Wenn ich jedoch häufig 'cout' und 'cin' verwende, schreibe ich: using std::cout; using std::cin;in die CPP-Datei (niemals in die Header-Datei, mit der sie sich verbreitet #include). Ich denke, dass niemand vernünftig jemals einen Stream coutoder nennen wird cin. ;)


7
Das ist eine lokale using- Deklaration , eine ganz andere Sache als eine using- Direktive .
sbi

25

Es ist schön, Code zu sehen und zu wissen, was er tut. Wenn ich sehe, std::coutweiß ich, dass das der coutStream der stdBibliothek ist. Wenn ich coutdann sehe, weiß ich es nicht. Es könnte der coutStrom der stdBibliothek sein. Oder es könnten int cout = 0;zehn Zeilen höher in derselben Funktion sein. Oder eine staticVariable mit dem Namen coutin dieser Datei. Es könnte alles sein.

Nehmen Sie jetzt eine Millionen-Zeilen-Codebasis, die nicht besonders groß ist, und suchen Sie nach einem Fehler, was bedeutet, dass Sie wissen, dass diese eine Million Zeilen eine Zeile enthält, die nicht das tut, was sie tun soll. cout << 1;könnte einen static intNamen lesen cout, ihn um ein Bit nach links verschieben und das Ergebnis wegwerfen. Auf der Suche nach einem Fehler müsste ich das überprüfen. Kannst du sehen, wie ich es wirklich wirklich vorziehe zu sehen std::cout?

Es ist eines dieser Dinge, die eine wirklich gute Idee zu sein scheinen, wenn Sie Lehrer sind und nie Code schreiben und pflegen mussten, um ihren Lebensunterhalt zu verdienen. Ich liebe es, Code zu sehen, wo (1) ich weiß, was er tut; und (2) ich bin zuversichtlich, dass die Person, die es schreibt, wusste, was es tut.


4
Woher wissen Sie, dass "std :: cout << 1" kein statisches int mit dem Namen cout im std-Namespace liest, indem es um eins verschoben und das Ergebnis weggeworfen wird? Auch woher weißt du was "<<" macht;) ??? ... scheint diese Antwort kein guter Datenpunkt zu sein, um "Verwendung" zu vermeiden.
Nyholku

4
Wenn jemand std :: cout als Ganzzahl neu definiert hat, ist Ihr Problem nicht technisch, sondern sozial - jemand hat es für Sie. (und Sie sollten wahrscheinlich auch alle Header auf Dinge wie #define true false usw. überprüfen)
Jeremy Friesner

2
Wenn ich cout sehe, weiß ich, dass es immer std :: cout ist. Wenn ich falsch liege, ist es das Problem der Person, die diesen Code geschrieben hat, nicht ich :)
Tien Do

22

Es geht darum, Komplexität zu managen. Wenn Sie den Namespace verwenden, werden Dinge eingezogen, die Sie nicht möchten, und daher wird das Debuggen möglicherweise schwieriger (ich sage möglicherweise). Die Verwendung von std :: überall ist schwieriger zu lesen (mehr Text und all das).

Pferde für Kurse - verwalten Sie Ihre Komplexität so gut Sie können und fühlen Sie sich in der Lage.


18

Erwägen

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // Uh oh
};

Beachten Sie, dass dies ein einfaches Beispiel ist. Wenn Sie Dateien mit 20 Includes und anderen Importen haben, müssen Sie eine Menge Abhängigkeiten durchlaufen, um das Problem herauszufinden. Das Schlimmste daran ist, dass Sie abhängig von den widersprüchlichen Definitionen in anderen Modulen nicht verwandte Fehler erhalten können.

Es ist nicht schrecklich, aber Sie sparen sich Kopfschmerzen, wenn Sie es nicht in Header-Dateien oder im globalen Namespace verwenden. Es ist wahrscheinlich in Ordnung, dies in sehr begrenzten Bereichen zu tun, aber ich hatte nie ein Problem damit, die zusätzlichen fünf Zeichen einzugeben, um zu klären, woher meine Funktionen stammen.


18
  1. Sie müssen in der Lage sein, Code zu lesen, der von Personen geschrieben wurde, die andere Meinungen zu Stil und Best Practices haben als Sie.

  2. Wenn Sie nur verwenden cout, wird niemand verwirrt. Wenn jedoch viele Namespaces herumfliegen und Sie diese Klasse sehen und nicht genau wissen, was sie bewirkt, fungiert der explizite Namespace als eine Art Kommentar. Sie können auf den ersten Blick sehen, "oh, das ist eine Dateisystemoperation" oder "das macht Netzwerkkram".


17

Die gleichzeitige Verwendung vieler Namespaces ist offensichtlich ein Rezept für eine Katastrophe, verwendet jedoch nur den Namespace stdund nur den Namespacestd ist meiner Meinung nach keine so große Sache, da eine Neudefinition nur durch Ihren eigenen Code erfolgen kann ...

Betrachten Sie sie einfach als reservierte Namen wie "int" oder "class" und das war's.

Die Leute sollten aufhören, so anal zu sein. Ihr Lehrer hatte die ganze Zeit recht. Verwenden Sie einfach EINEN Namespace. Das ist der springende Punkt bei der Verwendung von Namespaces. Sie sollten nicht mehr als eine gleichzeitig verwenden. Es sei denn, es ist dein eigenes. Eine Neudefinition wird also nicht stattfinden.


Kollisionen zu schaffen , ist nicht so schwer - kurze Strings mögen min, endund lessim erscheinen std::Namespace. Aber jetzt, wo std::Tausende von Symbolen enthalten sind, ist es für den Leser nützlich zu wissen, woher ein neues Symbol kommt, das er möglicherweise nicht kennt.
Tom Swirly

Der Standard-Namespace existiert, weil Personen, entweder Sie, Ihre Kollegen oder Personen, die von Ihnen verwendete Middleware schreiben, nicht immer klug sind, Funktionen in Namespaces einzufügen. Auf diese Weise können Sie alles von std :: und nichts anderes importieren, während Sie dennoch eine Kollision zwischen beispielsweise std :: min und dem Vermächtnis :: min () eines anderen aus der Zeit vor dem Zeitpunkt aufrufen, als es in std war.
Aiken Drum

14

Ich stimme den anderen hier zu, möchte aber auf die Bedenken hinsichtlich der Lesbarkeit eingehen. Sie können all dies vermeiden, indem Sie einfach typedefs oben in Ihrer Datei-, Funktions- oder Klassendeklaration verwenden.

Normalerweise verwende ich es in meiner Klassendeklaration, da Methoden in einer Klasse in der Regel mit ähnlichen Datentypen (den Mitgliedern) umgehen und ein typedef die Möglichkeit bietet, einen Namen zuzuweisen, der im Kontext der Klasse von Bedeutung ist. Dies unterstützt tatsächlich die Lesbarkeit in den Definitionen der Klassenmethoden.

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

und in der Umsetzung:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

im Gegensatz zu:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

oder:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}

Nur ein kleiner Kommentar, während typedef nützlich ist, würde ich in Betracht ziehen, eine Klasse zu erstellen, die Linien darstellt, anstatt typedef zu verwenden.
Eyal Solnik

14

Ein konkretes Beispiel zur Klärung des Problems. Stellen Sie sich eine Situation, wo Sie zwei Bibliotheken haben, foound bar, jede mit ihrem eigenen Namensraum:

namespace foo {
    void a(float) { /* Does something */ }
}

namespace bar {
    ...
}

Nehmen wir nun an, Sie verwenden foound barzusammen in Ihrem eigenen Programm wie folgt:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

An diesem Punkt ist alles in Ordnung. Wenn Sie Ihr Programm ausführen, wird "etwas tun" ausgeführt. Aber später aktualisieren Sie barund sagen wir, es hat sich geändert wie folgt:

namespace bar {
    void a(float) { /* Does something completely different */ }
}

An dieser Stelle wird ein Compilerfehler angezeigt:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

Sie müssen also einige Wartungsarbeiten durchführen, um zu verdeutlichen, dass "a" bedeutet foo::a. Das ist unerwünscht, aber zum Glück ist es ziemlich einfach (einfach foo::vor allen Anrufen hinzufügena dass der Compiler dies als mehrdeutig markiert).

Stellen Sie sich jedoch ein alternatives Szenario vor, in dem sich die Leiste geändert hat, um stattdessen so auszusehen:

namespace bar {
    void a(int) { /* Does something completely different */ }
}

An diesem Punkt a(42)bindet sich Ihr Aufruf, plötzlich an etwas zu binden, bar::aanstatt foo::aetwas zu tun, und es tut etwas völlig anderes. Keine Compilerwarnung oder so. Ihr Programm beginnt nur stillschweigend, etwas völlig anderes als zuvor zu tun.

Wenn Sie einen Namespace verwenden, riskieren Sie ein solches Szenario, weshalb es für Benutzer unangenehm ist, Namespaces zu verwenden. Je mehr Dinge sich in einem Namespace befinden, desto größer ist das Risiko von Konflikten, sodass die Verwendung des Namespace für die Benutzer möglicherweise noch unangenehmer iststd (aufgrund der Anzahl der Dinge in diesem Namespace) als für andere Namespaces.

Letztendlich ist dies ein Kompromiss zwischen Beschreibbarkeit und Zuverlässigkeit / Wartbarkeit. Die Lesbarkeit kann ebenfalls berücksichtigt werden, aber ich konnte Argumente dafür in beide Richtungen sehen. Normalerweise würde ich sagen, dass Zuverlässigkeit und Wartbarkeit wichtiger sind, aber in diesem Fall zahlen Sie ständig die Kosten für die Beschreibbarkeit für eine ziemlich seltene Auswirkung auf Zuverlässigkeit / Wartbarkeit. Der "beste" Kompromiss bestimmt Ihr Projekt und Ihre Prioritäten.


Das zweite Szenario macht den Deal für mich. Wieder keine Namespaces. Solche subtilen Änderungen in der Funktionalität können unter der Haube nicht unentdeckt bleiben.
safe_malloc

13

Ein Namespace ist ein benannter Bereich. Namespaces werden verwendet, um verwandte Deklarationen zu gruppieren und separate Elemente getrennt zu halten. Beispielsweise können zwei separat entwickelte Bibliotheken denselben Namen verwenden, um auf verschiedene Elemente zu verweisen, ein Benutzer kann jedoch weiterhin beide verwenden:

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    // ...
}

namespace Yourlib{
    class Stack{ /* ... */ };
    // ...
}

void f(int max) {
    Mylib::Stack<int> s1(max); // Use my stack
    Yourlib::Stack    s2(max); // Use your stack
    // ...
}

Das Wiederholen eines Namespace-Namens kann sowohl für Leser als auch für Schriftsteller eine Ablenkung sein. Folglich kann angegeben werden, dass Namen aus einem bestimmten Namespace ohne explizite Qualifikation verfügbar sind. Zum Beispiel:

void f(int max) {
    using namespace Mylib; // Make names from Mylib accessible
    Stack<int> s1(max); // Use my stack
    Yourlib::Stack s2(max); // Use your stack
    // ...
}

Namespaces bieten ein leistungsstarkes Tool für die Verwaltung verschiedener Bibliotheken und verschiedener Codeversionen. Insbesondere bieten sie dem Programmierer Alternativen dazu, wie explizit auf einen nichtlokalen Namen verwiesen werden soll.

Quelle: Ein Überblick über die C ++ - Programmiersprache von Bjarne Stroustrup


4
Sehr interessant, dass diese Antwort, die auf der Anleitung von keinem anderen basiert, den Bjarne Stroustrup verdient hat -2 ... Junge Bjarne muss ein armer und unerfahrener Programmierer gewesen sein, als er diese Funktion in C ++
einführte

@nyholku: Sehen Sie das .
sbi

10

Ein Beispiel, bei dem using namespace stdein Kompilierungsfehler aufgrund der Mehrdeutigkeit der Zählung ausgelöst wird, was auch eine Funktion in der Algorithmusbibliothek ist.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}

2
::count--Problem gelöst. Normalerweise haben Sie mehr Inhalte aus dem Standard-Namespace als aus anderen Ländern. Wenn Sie also die Namespace-Direktive verwenden, sparen Sie sich möglicherweise die Eingabe.
PSkocik

Das eigentliche Problem hierbei ist, dass C ++ immer noch Namespace-freie Globals hat. Dies und die Tatsache, dass 'dies' in Methoden impliziert ist, verursacht so viele Fehler und Probleme, dass ich sie selbst mit der richtigen 'count'-Variablen nicht einmal zählen kann. ;)
Aiken Drum

9

Dies verschlechtert die Leistung Ihrer Software oder Ihres Projekts nicht. Die Aufnahme des Namespace am Anfang Ihres Quellcodes ist nicht schlecht. Die Aufnahme der using namespace stdAnweisung hängt von Ihren Anforderungen und der Art und Weise ab, wie Sie die Software oder das Projekt entwickeln.

Das namespace stdenthält die C ++ - Standardfunktionen und -variablen. Dieser Namespace ist nützlich, wenn Sie häufig die C ++ - Standardfunktionen verwenden.

Wie auf dieser Seite erwähnt :

Die Anweisung mit dem Namespace std wird im Allgemeinen als schlechte Praxis angesehen. Die Alternative zu dieser Anweisung besteht darin, den Namespace, zu dem der Bezeichner gehört, mit dem Bereichsoperator (: :) jedes Mal anzugeben, wenn wir einen Typ deklarieren.

Und siehe diese Meinung :

Es ist kein Problem, "using namespace std" in Ihrer Quelldatei zu verwenden, wenn Sie den Namespace stark nutzen und sicher wissen, dass nichts kollidieren wird.

Einige Leute hatten gesagt, dass es eine schlechte Praxis ist, die using namespace stdin Ihre Quelldateien aufzunehmen, da Sie von diesem Namespace aus alle Funktionen und Variablen aufrufen. Wenn Sie eine neue Funktion mit demselben Namen wie eine andere in der enthaltene Funktion definieren namespace stdmöchten, überladen Sie die Funktion und es können Probleme beim Kompilieren oder Ausführen auftreten. Es wird nicht wie erwartet kompiliert oder ausgeführt.

Wie auf dieser Seite erwähnt :

Die Anweisung erspart uns zwar die Eingabe von std ::, wenn wir auf eine im std-Namespace definierte Klasse oder einen Typ zugreifen möchten, importiert jedoch den gesamten std-Namespace in den aktuellen Namespace des Programms. Nehmen wir ein paar Beispiele, um zu verstehen, warum dies möglicherweise nicht so gut ist

...

Jetzt, zu einem späteren Zeitpunkt der Entwicklung, möchten wir eine andere Version von cout verwenden, die benutzerdefiniert in einer Bibliothek namens "foo" implementiert ist (zum Beispiel).

...

Beachten Sie, wie es eine Mehrdeutigkeit gibt, auf welche Bibliothek cout verweist? Der Compiler erkennt dies möglicherweise und kompiliert das Programm nicht. Im schlimmsten Fall kann das Programm zwar noch kompilieren, aber die falsche Funktion aufrufen, da wir nie angegeben haben, zu welchem ​​Namespace der Bezeichner gehört.


8

Ich denke nicht, dass es unter allen Umständen unbedingt eine schlechte Praxis ist, aber Sie müssen vorsichtig sein, wenn Sie es verwenden. Wenn Sie eine Bibliothek schreiben, sollten Sie wahrscheinlich die Bereichsauflösungsoperatoren mit dem Namespace verwenden, um zu verhindern, dass Ihre Bibliothek mit anderen Bibliotheken in Kontakt kommt. Für Code auf Anwendungsebene sehe ich nichts Falsches daran.


7

"Warum 'Namespace std verwenden;' als schlechte Praxis in C ++ angesehen? "

Ich habe es anders herum ausgedrückt: Warum wird das Eingeben von fünf zusätzlichen Zeichen von manchen als umständlich angesehen?

Denken Sie beispielsweise daran, eine numerische Software zu schreiben. Warum sollte ich überhaupt in Betracht ziehen, meinen globalen Namespace zu verschmutzen, indem ich "std :: vector" auf "vector" reduziere, wenn "vector" eines der wichtigsten Konzepte der Problemdomäne ist?


19
Es sind nicht nur 5 zusätzliche Zeichen; Die 5 zusätzlichen Zeichen werden jedes Mal angezeigt, wenn Sie auf einen Objekttyp in der Standardbibliothek verweisen. Was, wenn Sie die Standardbibliothek sehr häufig verwenden, häufig vorkommt. Es sind also realistischere Tausende von zusätzlichen Zeichen in einem Programm mit anständiger Größe. Vermutlich wurde die 'using'-Direktive der Sprache hinzugefügt, damit sie verwendet werden kann ...
Jeremy Friesner

5
Es sind nicht jedes Mal 5 zusätzliche Zeichen, sondern 5 Zeichen und wahrscheinlich ein paar Mausklicks, um ein Menü aufzurufen und im Editor Ihrer Wahl ein Suchen und Ersetzen durchzuführen.
DaveWalley

1
Lesbarkeit. cout << hex << setw(4) << i << endl;ist leichter zu lesen alsstd::cout << std::hex << std::setw(4) << i << std::endl;
oz1cz

16
Und noch schlimmer: std::map<std::string,std::pair<std::string,std::string>>ist schrecklich im Vergleich zu map<string,pair<string,string>>.
oz1cz

4
Es ist eine gute Praxis, Ihre STL-Container trotzdem zu tippen, damit std :: dort wirklich keine Rolle spielt. Und C ++ 11 brachte uns das Auto-Schlüsselwort, das die Dinge noch einfacher macht, wenn wir beispielsweise Iteratoren verwenden.
Juzzlin

7

Ich stimme anderen zu - es fragt nach Namenskonflikten, Unklarheiten und dann ist die Tatsache, dass es weniger explizit ist. Während ich die Verwendung von sehen kann using, ist es meine persönliche Präferenz, sie einzuschränken. Ich würde auch stark darüber nachdenken, worauf einige andere hingewiesen haben:

Wenn Sie einen Funktionsnamen suchen möchten, der möglicherweise ein ziemlich gebräuchlicher Name ist, ihn aber nur im stdNamespace finden möchten (oder umgekehrt - Sie möchten alle Aufrufe ändern, die sich nicht im Namespace std, Namespace Xusw. befinden), Wie schlagen Sie das vor?

Sie könnten ein Programm schreiben, um dies zu tun, aber wäre es nicht besser, Zeit damit zu verbringen, an Ihrem Projekt selbst zu arbeiten, als ein Programm zu schreiben, um Ihr Projekt zu warten?

Persönlich stört mich das std::Präfix eigentlich nicht . Ich mag das Aussehen mehr als es nicht zu haben. Ich weiß nicht, ob das daran liegt, dass es explizit ist und zu mir sagt "das ist nicht mein Code ... ich verwende die Standardbibliothek" oder ob es etwas anderes ist, aber ich denke, es sieht besser aus. Dies könnte seltsam sein, da ich erst vor kurzem in C ++ eingestiegen bin (C und andere Sprachen werden viel länger verwendet und immer noch verwendet und C ist meine Lieblingssprache aller Zeiten, direkt über der Assembly).

Es gibt noch eine andere Sache, obwohl sie etwas mit dem oben Gesagten zu tun hat und worauf andere hinweisen. Obwohl dies eine schlechte Praxis sein kann, reserviere ich manchmal std::namedie Standardbibliotheksversion und den Namen für die programmspezifische Implementierung. Ja, in der Tat könnte dies Sie beißen und Sie hart beißen, aber es kommt darauf an, dass ich dieses Projekt von Grund auf neu gestartet habe und ich der einzige Programmierer dafür bin. Beispiel: Ich überlade std::stringund nenne es string. Ich habe hilfreiche Ergänzungen. Ich habe es teilweise aufgrund meiner C- und Unix-Tendenz (+ Linux) zu Kleinbuchstaben gemacht.

Außerdem können Sie Namespace-Aliase haben. Hier ist ein Beispiel dafür, wo es nützlich ist, auf das möglicherweise nicht Bezug genommen wurde. Ich benutze den C ++ 11 Standard und speziell mit libstdc ++. Nun, es hat keine vollständige std::regexUnterstützung. Sicher, es wird kompiliert, aber es löst eine Ausnahme aus, da es sich um einen Fehler des Programmierers handelt. Aber es ist mangelnde Umsetzung.

So habe ich es gelöst. Installieren Sie den regulären Ausdruck von Boost und verknüpfen Sie ihn. Anschließend gehe ich folgendermaßen vor: Wenn libstdc ++ ihn vollständig implementiert hat, muss ich nur diesen Block entfernen und der Code bleibt gleich:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

Ich werde nicht darüber streiten, ob das eine schlechte Idee ist oder nicht. Ich werde jedoch argumentieren, dass es es für mein Projekt sauber hält und es gleichzeitig spezifisch macht: Richtig, ich muss Boost verwenden, aber ich verwende es so, wie es libstdc ++ irgendwann haben wird. Ja, das Starten eines eigenen Projekts und das Beginnen mit einem Standard (...) am Anfang trägt wesentlich dazu bei, Wartung, Entwicklung und alles, was mit dem Projekt zu tun hat, zu unterstützen!

Nur um etwas zu verdeutlichen: Ich halte es eigentlich nicht für eine gute Idee, einen Namen einer Klasse / was auch immer in der STL absichtlich und genauer anstelle von zu verwenden. Die Zeichenfolge ist für mich die Ausnahme (ignorieren Sie das erste, obige oder zweite Wortspiel, wenn Sie müssen) für mich, da mir die Idee von 'Zeichenfolge' nicht gefallen hat.

So wie es ist, bin ich immer noch sehr voreingenommen gegenüber C und voreingenommen gegenüber C ++. Sparsame Details, vieles, woran ich arbeite, passt mehr zu C (aber es war eine gute Übung und eine gute Möglichkeit, mich dazu zu bringen, a. Eine andere Sprache zu lernen und b. Nicht weniger voreingenommen gegenüber Objekten / Klassen / usw. zu sein, was vielleicht besser gesagt wird als weniger verschlossen, weniger arrogant und mehr akzeptierend.). Aber was nützlich ist , ist das, was einige bereits vorgeschlagen haben: Ich verwende tatsächlich list (es ist ziemlich allgemein, nicht wahr?) Und sortiere (dasselbe), um zwei zu benennen, die einen Namenskonflikt verursachen würden, wenn ich das tun würde using namespace std;, und so weiter Zu diesem Zweck bevorzuge ich es, spezifisch zu sein, die Kontrolle zu behalten und zu wissen, dass ich es spezifizieren muss, wenn ich beabsichtige, dass es die Standardverwendung ist. Einfach gesagt: keine Annahme erlaubt.

Und was Boosts Regex angeht std. Ich mache das für die zukünftige Integration und - ich gebe wieder zu, dass dies Voreingenommenheit ist - ich denke nicht, dass es so hässlich ist wie boost::regex:: .... In der Tat ist das eine andere Sache für mich. Es gibt viele Dinge in C ++, die ich in Aussehen und Methoden noch nicht vollständig akzeptiert habe (ein weiteres Beispiel: Variadische Vorlagen versus Var-Argumente [obwohl ich zugebe, dass Variadische Vorlagen sehr, sehr nützlich sind!]). Sogar diejenigen, die ich akzeptiere, waren schwierig und ich habe immer noch Probleme mit ihnen.


1
Das Erweitern des stdNamespace ist ein undefiniertes Verhalten und sollte daher niemals durchgeführt werden.
Tambre

7

Nach meinen Erfahrungen können Sie, wenn Sie mehrere Bibliotheken haben, die beispielsweise verwenden cout, aber für einen anderen Zweck die falsche verwenden cout.

Wenn ich zum Beispiel using namespace std;und using namespace otherlib;und nur cout(was zufällig in beiden ist) anstelle von std::cout(oder 'otherlib::cout') eingebe, verwenden Sie möglicherweise die falsche und erhalten Fehler. Es ist viel effektiver und effizienter zu bedienen std::cout.


6

Bei nicht qualifizierten importierten Bezeichnern benötigen Sie externe Suchwerkzeuge wie grep , um herauszufinden, wo Bezeichner deklariert sind. Dies erschwert das Nachdenken über die Programmkorrektheit.


6

Es hängt davon ab, wo es sich befindet. Wenn es sich um einen allgemeinen Header handelt, verringern Sie den Wert des Namespace, indem Sie ihn mit dem globalen Namespace zusammenführen. Denken Sie daran, dies könnte eine gute Möglichkeit sein, Modulglobale zu erstellen.


6

Dies ist eine schlechte Praxis, die oft als globale Verschmutzung durch Namespaces bezeichnet wird. Probleme können auftreten, wenn mehr als ein Namespace denselben Funktionsnamen mit Signatur hat. Dann muss der Compiler nicht eindeutig entscheiden, welchen er aufrufen möchte std::cout. Dies alles kann vermieden werden, wenn Sie den Namespace mit Ihrem Funktionsaufruf wie angeben . Hoffe das hilft. :) :)


5

Um Ihre Frage zu beantworten, sehe ich das praktisch so: Viele Programmierer (nicht alle) rufen den Namespace std auf. Daher sollte man es sich zur Gewohnheit machen, KEINE Dinge zu verwenden, die die gleichen Namen wie im Namespace std beeinflussen oder verwenden. Das ist sehr selbstverständlich, aber nicht so sehr im Vergleich zu der Anzahl möglicher zusammenhängender Wörter und Pseudonyme, die genau genommen gefunden werden können.

Ich meine wirklich ... zu sagen "Verlasse dich nicht darauf, dass dies vorhanden ist" bedeutet nur, dich darauf vorzubereiten, dass es NICHT vorhanden ist. Sie werden ständig Probleme haben, Codefragmente auszuleihen und ständig zu reparieren. Halten Sie einfach Ihre benutzerdefinierten und ausgeliehenen Inhalte in einem begrenzten Umfang, wie sie sein sollten, und gehen Sie SEHR sparsam mit Globals um (ehrlich gesagt sollten Globals fast immer das letzte Mittel sein, um "jetzt kompilieren, später vernünftig"). Wirklich, ich denke, es ist ein schlechter Rat von Ihrem Lehrer, weil die Verwendung von std sowohl für "cout" als auch für "std :: cout" funktioniert, aber NICHT für "std :: cout". Sie werden nicht immer das Glück haben, Ihren gesamten Code zu schreiben.

HINWEIS: Konzentrieren Sie sich nicht zu sehr auf Effizienzprobleme, bis Sie tatsächlich ein wenig über die Funktionsweise von Compilern gelernt haben. Mit ein wenig Erfahrung im Codieren müssen Sie nicht so viel über sie lernen, bevor Sie erkennen, wie viel sie in der Lage sind, guten Code in etwas Einfaches zu verallgemeinern. Genauso einfach, als ob Sie das Ganze in C geschrieben hätten. Guter Code ist nur so komplex, wie er sein muss.


Angesichts der Tatsache, wie viele Leute sich nützlicher Standardbibliotheksfunktionen nicht bewusst zu sein scheinen ( <algorithm>z. B. Dinge neu erfinden ), scheint es ein bisschen schwierig zu sein, sich vorzustellen, dass dieselben Personen diese Kennungen zuverlässig vermeiden könnten. Sehen Sie sich Ihren eigenen Code an und sagen Sie mir, dass Sie niemals eine Variable oder Funktion aufgerufen haben count. Oder distance, oder log, destroy, launch, visit, beta, sample, messages, clamp, erase, copy, modulus, left, etc. Nicht alle die Kennungen noch nicht in erwähnen , stddass brechen Sie den Code , wenn C ++ 35 kommt ...
Toby Speight
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.