c++ what Warum ist die Verwendung von Namespace std eine schlechte Praxis?




what is using namespace std (30)

Verwenden Sie es nicht global

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

  • Sie stören den Namensraum, in dem Sie programmieren.
  • Leser werden Schwierigkeiten haben, zu erkennen, woher ein bestimmter Bezeichner kommt, wenn Sie viele using namespace xyz .
  • Was für andere Leser Ihres Quellcodes gilt, gilt für den häufigsten Leser noch mehr: Sie selbst. Kommen Sie in ein oder zwei Jahren wieder und schauen Sie ...
  • Wenn Sie nur über die using namespace std sprechen using namespace std Sie möglicherweise nicht über all das Bescheidene informiert - und wenn Sie ein neues #include hinzufügen oder zu einer neuen C ++ - #include wechseln, werden möglicherweise Namenskonflikte angezeigt, die Sie nicht kennen.

Sie können es lokal verwenden

Verwenden Sie es lokal (fast) frei. Dies verhindert natürlich die Wiederholung von std:: - und Wiederholung ist auch schlecht.

Ein Idiom für die lokale Verwendung

In C ++ 03 gab es einen Idiom - Boilerplate-Code - zur Implementierung einer swap Funktion für Ihre Klassen. Es wurde empfohlen, dass Sie tatsächlich einen lokalen 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 bewirkt die folgende Magie:

  • Der Compiler wählt std::swap für value_ , dh void std::swap(int, int) .
  • Wenn Sie einen void swap(Child&, Child&) überladen void swap(Child&, Child&) implementiert haben, wählt der Compiler diesen aus.
  • Wenn Sie diese Überladung nicht haben, verwendet der Compiler void std::swap(Child&,Child&) und versucht, diese auszutauschen.

Mit C ++ 11 gibt es keinen Grund mehr, dieses Muster zu verwenden. Die Implementierung von std::swap wurde geändert, um eine potenzielle Überlastung zu finden und sie auszuwählen.

https://code.i-harness.com

Ich habe von anderen using namespace std dass das Schreiben using namespace std im Code falsch ist und ich stattdessen std::cout und std::cin direkt verwenden sollte.

Warum ist die using namespace std eine schlechte Praxis? Ist es ineffizient oder riskiert es mehrdeutige Variablen (Variablen, die denselben Namen wie eine Funktion im std Namespace haben)? Beeinträchtigt es die Leistung?


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

  2. Wenn Sie nur Cout verwenden, wird niemand verwirrt. Wenn jedoch viele Namespaces herumfliegen und diese Klasse angezeigt wird und Sie nicht genau wissen, was sie tut, wird der explizite Namespace als Art Kommentar verwendet. Sie sehen auf den ersten Blick, "oh, das ist eine Dateisystemoperation" oder "das macht Netzwerksachen".


Das Problem bei der using namespace in den Header-Dateien Ihrer Klassen besteht darin, dass jeder, der Ihre Klassen verwenden möchte (indem er Ihre Header-Dateien einschließt), auch diese anderen Namespaces "verwendet" (dh alles in den anderen Namespaces sehen).

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

Beachten Sie, dass einige Leute nicht mit meinem Spruch "Ich fühle mich frei" so sagen - weil eine using-Anweisung in einer cpp-Datei besser ist als in einem Header (da dies keine Auswirkungen auf Leute hat, die Ihre Header-Datei enthalten), glauben sie, dass es immer noch ist nicht gut (weil dies je nach Code die Implementierung der Klasse erschweren könnte). Dieses FAQ-Thema besagt:

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

Die FAQ schlägt zwei Alternativen vor:

  • Eine Verwendungserklärung:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Einfach std eingeben:

    std::cout << "Values:";
    

Die gleichzeitige Verwendung vieler Namespaces ist offensichtlich ein Desaster, aber die Verwendung von JUST Namespace std und nur Namespace std ist meiner Meinung nach keine große Sache, da Redefinition nur durch Ihren eigenen Code erfolgen kann.

Betrachten Sie sie einfach als reservierte Namen wie "int" oder "class" und das ist es.

Die Leute sollten aufhören, so anal zu sein. Dein Lehrer hatte die ganze Zeit Recht. Verwenden Sie einfach EINEN Namespace. Das ist der springende Punkt, wenn Namespaces an erster Stelle stehen. Sie dürfen nicht mehr als eine gleichzeitig verwenden. Es sei denn, es ist deine eigene. Eine erneute Definition wird also nicht stattfinden.


Dies hat nichts mit der Leistung zu tun. Aber bedenken Sie Folgendes: Sie verwenden zwei Bibliotheken namens Foo und Bar:

using namespace foo;
using namespace bar;

Alles funktioniert gut, Sie können Blah() von Foo und Quux() von Bar ohne Probleme Quux() . Aber eines Tages aktualisieren Sie auf eine neue Version von Foo 2.0, die jetzt eine Funktion namens Quux() bietet. Jetzt haben Sie einen Konflikt: Sowohl Foo 2.0 als auch Bar importieren Quux() in Ihren globalen Namespace. Dies erfordert einige Korrekturen, insbesondere wenn die Funktionsparameter übereinstimmen.

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


Ein weiterer Grund ist die Überraschung.

Wenn ich cout << blah sehe, statt std::cout << blah

Ich denke was ist das cout ? Ist es der normale cout ? Ist es etwas Besonderes?


Erfahrene Programmierer verwenden, was ihre Probleme löst, und vermeiden, was neue Probleme verursacht, und sie vermeiden aus genau diesem Grund die Direktiven auf Header-Dateiebene.

Erfahrene Programmierer versuchen auch, die vollständige Qualifizierung der 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 ausschalten, zu anderen Zeitpunkten, wenn sie disambiguieren möchten.

Also die folgenden sind in Ordnung:

  1. Gebrauchsanweisungen und Verwendungsdeklarationen auf Funktionsebene in Implementierungen von Funktionen
  2. Verwendungsdeklarationen auf Quelldateibasis in Quelldateien
  3. (Manchmal) using-Direktiven auf Quellendateienebene

Es geht darum, die Komplexität zu beherrschen. Die Verwendung des Namespaces zieht Dinge ein, die Sie nicht möchten, und macht es daher möglicherweise schwieriger zu debuggen (sage ich 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, wie Sie es am besten können und fühlen können.


Es ist schön, Code zu sehen und zu wissen, was er tut. Wenn ich std::cout sehe, weiß ich, dass dies der cout Stream der std Bibliothek ist. Wenn ich cout sehe, weiß ich es nicht. Es könnte der cout Stream der std Bibliothek sein. Oder es könnte ein int cout = 0; zehn Zeilen höher in derselben Funktion. Oder eine static Variable namens cout in dieser Datei. Es könnte alles sein.

Nehmen Sie jetzt eine Million Zeilencode-Basis, die nicht besonders groß ist, und Sie suchen nach einem Fehler. Das heißt, Sie wissen, dass es eine Zeile in dieser eine Million Zeilen gibt, die nicht das tut, was sie tun soll. cout << 1; konnte ein static int Namen cout lesen, es 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, dass ich wirklich wirklich lieber std::cout sehe?

Es ist eines dieser Dinge, die eine wirklich gute Idee sind, wenn Sie Lehrer sind und niemals Code schreiben müssen, 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 sie schreibt, wusste, was sie tut.


Ich bin damit einverstanden, dass es nicht global verwendet werden sollte, es jedoch nicht so schlimm ist, lokal wie in einem 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 wurden mögliche Namenskollisionen und Mehrdeutigkeiten aufgrund ihrer Komposition aufgelöst.

Dort explizit deklarierte Namen (einschließlich Namen, die mit using-Deklarationen wie His_lib::String deklariert wurden) haben Vorrang vor Namen, die in einem anderen Bereich von einer using-Direktive (unter using namespace Her_lib ) using namespace Her_lib .


Ich habe kürzlich eine Beschwerde über Visual Studio 2010 . Es stellte sich heraus, dass so ziemlich alle Quelldateien diese zwei Zeilen hatten:

using namespace std;
using namespace boost;

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

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


Ich halte es auch für eine schlechte Praxis. Warum? Nur eines Tages dachte ich, dass die Funktion eines Namensraums darin besteht, die Dinge zu unterteilen, damit ich es nicht verderben darf, indem ich alles in eine globale Tasche stecke. Wenn ich jedoch häufig 'cout' und 'cin' verwende, schreibe ich: using std::cout; using std::cin; using std::cout; using std::cin; in cpp-Datei (niemals in der Header-Datei, wenn sie mit #include ). Ich denke, niemand wird einen Stream cout oder cin . ;)


Ich stimme mit allem überein, 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 eindeutig für einige Ihrer Aufrufe von Quux() besser Quux() als der Code bar::Quux() Ihr Code seit Jahren aufgerufen hat. Dann wird Ihr Code immer noch kompiliert , aber er ruft lautlos die falsche Funktion auf und weiß, was. Das ist so schlimm wie es nur geht.

Beachten Sie, dass der std Namespace eine Unmenge von Bezeichnern enthält, von denen viele sehr häufig vorkommen (Denkliste, sort , string , iterator usw.), die sehr wahrscheinlich auch in anderem Code vorkommen.

Wenn Sie dies für unwahrscheinlich halten: Es wurde eine Frage zu gestellt, bei der dies ziemlich genau passierte (falsche Funktion wegen fehlendem std:: -Präfix genannt), etwa ein halbes Jahr, nachdem ich diese Antwort gab. Here ist ein anderes, jüngeres Beispiel für eine solche Frage. Das ist also ein echtes Problem.

Hier noch ein weiterer Datenpunkt: Vor vielen, vielen Jahren habe ich es auch als störend empfunden, alles aus der Standardbibliothek mit std:: voranstellen zu müssen. Dann arbeitete ich in einem Projekt, bei dem zu Beginn entschieden wurde, dass sowohl Richtlinien als auch Deklarationen mit Ausnahme von Funktionsbereichen verboten sind. Erraten Sie, was? Die meisten von uns brauchten einige 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 tatsächlich lesbarer wird . 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, auch Sie finden leichter, auf welchen Bezeichner verwiesen wird.

In einem Jahrzehnt wuchs dieses Projekt um mehrere Millionen Codezeilen. Da diese Diskussionen immer wieder auftauchen, war ich einmal gespannt, wie oft der (erlaubte) Funktionsumfang tatsächlich im Projekt verwendet wurde. Ich grub die Quellen dafür und fand nur ein oder zwei Dutzend Orte, an denen es benutzt wurde. Für mich bedeutet dies, dass Entwickler, wenn sie einmal versucht wurden, std:: nicht so schmerzhaft finden, dass sie einmal pro 100 kLoC Anweisungen verwenden, selbst wenn sie verwendet werden dürfen.

Fazit: Das explizite Voranstellen von allem schadet nicht, ist gewöhnungsbedürftig und hat objektive Vorteile. Insbesondere macht es den Code für den Compiler und für menschliche Leser leichter zu interpretieren - und dies sollte wahrscheinlich das Hauptziel beim Schreiben von Code sein.


Kurzversion: Verwenden Sie keine globalen Deklarationen oder Anweisungen in Header-Dateien. Sie können sie gerne in Implementierungsdateien verwenden. Folgendes sagen Herb Sutter und Andrei Alexandrescu zu diesem Thema in den C ++ - Codierungsstandards.

Zusammenfassung

Namespace-Usings dienen Ihrer Bequemlichkeit und dürfen Sie nicht anderen zufügen: Schreiben Sie niemals eine using-Deklaration oder eine using-Direktive vor einer # include-Direktive.

Folgerung: Schreiben Sie in Header-Dateien keine Namespace-Ebene mit Anweisungen oder Deklarationen. explizit namespace-qualify alle namen. (Die zweite Regel folgt aus der ersten Regel, da Kopfzeilen niemals wissen können, welche anderen Kopfzeilen # enthalten sind.)

Diskussion

Kurz gesagt: Sie können und sollten Namespaces verwenden, indem Sie Deklarationen und Direktiven großzügig in Ihren Implementierungsdateien nach # include-Direktiven verwenden und sich dabei wohl fühlen. Trotz wiederholter gegenteiliger Behauptungen sind Namespaces, die Deklarationen und Anweisungen verwenden, kein Übel, und sie zerstören nicht den Zweck von Namespaces. Vielmehr machen sie Namespaces nutzbar .


Man sollte die Direktive nicht im globalen Bereich verwenden, insbesondere in Headern. Es gibt jedoch Situationen, in denen es sogar in einer Header-Datei angebracht 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 arbeiten kann (über Argument Dependent Lookup).


Wenn Sie die rechten Header-Dateien importieren, haben Sie plötzlich Namen wie hex , left , plus oder count in Ihrem globalen Gültigkeitsbereich. Dies kann überraschend sein, wenn Sie nicht wissen, dass std:: diese Namen enthält. Wenn Sie versuchen, diese Namen auch lokal zu verwenden, kann dies zu Verwirrung führen.

Wenn sich das Standardmaterial in einem eigenen Namensraum befindet, müssen Sie sich nicht um Namenskollisionen mit Ihrem Code oder anderen Bibliotheken sorgen.


Ein Beispiel, bei dem die Verwendung des Namespaces std aufgrund der Mehrdeutigkeit von count einen Komplikationsfehler auslöst, der auch eine Funktion in der Algorithmusbibliothek ist.

#include <iostream>

using namespace std;

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

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 Include-Dateien und anderen Importen haben, haben Sie eine Menge Abhängigkeiten, um das Problem zu lösen. Das Schlimmste daran ist, dass Sie in anderen Modulen abhängig von den Definitionen, die in Konflikt stehen, nicht zusammenhängende Fehler erhalten.

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 begrenztem Umfang zu tun, aber ich hatte noch nie Probleme, die zusätzlichen 5 Zeichen einzugeben, um zu klären, woher meine Funktionen kommen.


Ich stimme den anderen hier zu, möchte jedoch die Bedenken hinsichtlich der Lesbarkeit aufgreifen - 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 dazu tendieren, ähnliche Datentypen (die Member) zu behandeln, und ein Typedef ist eine Gelegenheit, einen Namen zuzuweisen, der im Kontext der Klasse aussagefähig ist. Dies erleichtert die Lesbarkeit der 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;
}

"Warum verwendet 'Namespace std;' als schlechte Praxis in C ++ betrachtet? "

Ich formuliere es anders herum: Warum wird das Tippen von 5 zusätzlichen Zeichen von manchen als umständlich angesehen?

Denken Sie zum Beispiel an das Schreiben einer numerischen Software. Warum sollte ich sogar in Betracht ziehen, meinen globalen Namespace zu verschmutzen, indem Sie "std :: vector" auf "vector" reduzieren, wenn "vector" eines der wichtigsten Konzepte der Problemdomäne ist?


Die Software- oder Projektleistung wird dadurch nicht schlechter. Die Einbeziehung des Namensraums zu Beginn Ihres Quellcodes ist nicht schlecht. Die Einbeziehung der using namespace stdAnleitung 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 hilfreich, wenn Sie häufig die C ++ - Standardfunktionen verwenden.

Wie auf dieser page :

Die Anweisung, die den Namespace std verwendet, wird im Allgemeinen als schlechte Praxis betrachtet. Die Alternative zu dieser Anweisung ist, den Namespace anzugeben, zu dem der Bezeichner mithilfe des Bereichsoperators (: :) gehört, wenn wir einen Typ deklarieren.

Und sehen Sie diese Meinung :

Die Verwendung von "using Namespace std" in Ihrer Quelldatei ist problemlos, wenn Sie den Namespace intensiv nutzen und sicher sind, dass nichts kollidiert.

Einige Leute hatten gesagt, dass es eine schlechte Praxis ist, das using namespace stdin Ihre Quelldateien aufzunehmen, da Sie aus diesem Namespace alle Funktionen und Variablen aufrufen. Wenn Sie eine neue Funktion definieren möchten, die denselben Namen wie eine andere in der Funktion namespace stdhat, würden Sie die Funktion überladen und es könnte zu Problemen beim Kompilieren oder Ausführen kommen. Es wird nicht wie erwartet kompiliert oder ausgeführt.

Wie auf dieser page :

Die Anweisung erspart uns zwar die Eingabe von std ::, wenn auf eine im std-Namespace definierte Klasse oder Typ zugegriffen werden soll, sie importiert jedoch den gesamten std-Namespace in den aktuellen Namespace des Programms. Nehmen wir einige Beispiele, um zu verstehen, warum dies nicht so gut ist

...

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

...

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


Dies ist eine schlechte Praxis, die häufig als globale Namensraumverschmutzung bezeichnet wird. Es können Probleme auftreten, wenn mehrere Namespaces denselben Funktionsnamen mit Signatur haben. Dann ist es für den Compiler mehrdeutig, zu entscheiden, welcher aufgerufen werden soll. Dies kann vermieden werden, wenn Sie den Namespace mit Ihrem Funktionsaufruf wie angeben std::cout. Hoffe das hilft. :)


Ein Namespace ist ein benannter Bereich. Namensräume werden verwendet, um zusammengehörige Deklarationen zu gruppieren und separate Elemente voneinander zu trennen. Beispielsweise können zwei separat entwickelte Bibliotheken denselben Namen verwenden, um auf verschiedene Elemente zu verweisen, ein Benutzer kann jedoch 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 Namensraumnamens kann sowohl für Leser als auch für Autoren eine Ablenkung sein. Folglich kann angegeben werden, dass Namen aus einem bestimmten Namespace ohne explizite Qualifizierung 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 leistungsfähiges Werkzeug für die Verwaltung verschiedener Bibliotheken und unterschiedlicher Code-Versionen. Sie bieten dem Programmierer insbesondere Alternativen, wie explizit auf einen nicht lokalen Namen verwiesen werden soll.

Quelle: Eine Übersicht über die Programmiersprache C ++ von Bjarne Stroustrup


Ein konkretes Beispiel, um das Anliegen zu verdeutlichen. Stellen Sie sich vor, Sie haben eine Situation, in der Sie 2 Bibliotheken, foo und bar, mit jeweils eigenem Namensraum haben:

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

namespace bar {
    ...
}

Nehmen wir an, Sie verwenden foo und bar 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, "tut es etwas". Aber später aktualisieren Sie die Leiste und sagen, es hat sich wie folgt geändert:

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

An dieser Stelle erhalten Sie einen Compiler-Fehler:

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 klären, welches 'a' Sie meinten (dh foo::a). Das ist wahrscheinlich unerwünscht, aber zum Glück ist es ziemlich einfach (fügen Sie einfach foo::alle Aufrufe hinzu, adie der Compiler als mehrdeutig kennzeichnet).

Stellen Sie sich jedoch ein alternatives Szenario vor, bei dem die Leiste stattdessen folgendermaßen geändert wurde:

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

An diesem Punkt a(42)bindet Ihr Aufruf plötzlich an bar::astatt foo::aund statt "etwas" zu tun, wird "etwas völlig anderes" ausgeführt. Keine Compiler-Warnung oder irgendetwas. Ihr Programm fängt einfach an, etwas völlig anderes als zuvor zu tun.

Wenn Sie einen Namespace verwenden, riskieren Sie ein solches Szenario. Aus diesem Grund ist es für die Benutzer unbequem, Namespaces zu verwenden. Je mehr Dinge in einem Namespace vorhanden sind, desto größer ist das Risiko eines Konflikts. Daher ist die Verwendung von Namespace std (aufgrund der Anzahl der Dinge in diesem Namespace) möglicherweise noch unbequemer als bei anderen Namespaces.

Letztendlich ist dies ein Kompromiss zwischen Beschreibbarkeit und Zuverlässigkeit / Wartbarkeit. Lesbarkeit kann auch einfließen, aber ich könnte Argumente dafür sehen. Normalerweise würde ich sagen, dass Zuverlässigkeit und Wartungsfreundlichkeit wichtiger sind, aber in diesem Fall müssen Sie ständig die Kosten für die Schreibbarkeit bezahlen, was sich auf die Zuverlässigkeit und Wartungsfreundlichkeit auswirkt. Der "beste" Kompromiss entscheidet über Ihr Projekt und Ihre Prioritäten.


Es hängt davon ab, wo es sich befindet. Wenn es sich um einen allgemeinen Header handelt, verringern Sie den Wert des Namespaces, indem Sie ihn mit dem globalen Namespace zusammenführen. Denken Sie daran, dies könnte ein guter Weg sein, um globale Module zu erstellen.


Ich denke nicht, dass dies unter allen Umständen 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 Köpfe mit anderen Bibliotheken verbindet. Für Code auf Anwendungsebene sehe ich nichts falsches.


Ich stimme mit anderen überein - es verlangt nach Namenskonflikten und Zweideutigkeiten, und dann ist es weniger explizit. Während ich die Verwendung von sehen kann using, ist es meine persönliche Präferenz, es 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 recht allgemeiner Name ist, Sie ihn aber nur im stdNamensraum finden möchten (oder umgekehrt - Sie möchten alle Aufrufe ändern, die NICHT im Namensraum std, Namensraum X, ...) Wie schlagen Sie dann vor? Sie könnten ein Programm dafür schreiben, aber wäre es nicht besser, Zeit für Ihr Projekt selbst zu verbringen, anstatt ein Programm zu schreiben, um Ihr Projekt aufrechtzuerhalten?

Persönlich stört mich das std::Präfix eigentlich nicht . Ich mag den Look mehr als ihn nicht zu haben. Ich weiß nicht, ob das so ist, weil 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 schöner aus. Dies mag seltsam sein, da ich erst kürzlich in C ++ eingestiegen bin (verwendet und noch viel länger C und andere Sprachen ist und C meine Lieblingssprache aller Zeiten ist, direkt über Assembly).

Es gibt noch eine andere Sache, obwohl es etwas mit dem oben genannten zu tun hat und worauf andere hinweisen. Obwohl dies eine schlechte Praxis sein kann, reserviere ich manchmal std::namefür die Standard-Bibliotheksversion und den Namen für die programmspezifische Implementierung. Ja, das könnte dich beißen und dich hart beißen, aber es kommt darauf an, dass ich dieses Projekt von vorne angefangen 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 zum Teil gemacht, weil meine Neigung zu C und Unix (+ Linux) zu Kleinbuchstaben neigt.

Außerdem können Sie Namespace-Aliase verwenden. Hier ist ein Beispiel, wo es nützlich ist, worauf möglicherweise nicht verwiesen wurde. Ich verwende den C ++ 11-Standard und speziell mit libstdc ++. Nun, es hat keine vollständige std::regexUnterstützung. Sicher, es wird kompiliert, aber es wird eine Ausnahme ausgegeben, da es ein Fehler am Ende des Programmierers ist. Aber es fehlt an Implementierung. So habe ich es gelöst. Installieren Sie den regulären Ausdruck von Boost und verknüpfen Sie ihn. Dann mache ich Folgendes, damit ich, wenn libstdc ++ es vollständig implementiert hat, nur diesen Block entfernen muss und der Code gleich bleibt:

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 für mein Projekt sauber bleibt und es gleichzeitig konkret macht: Wahr, ich muss Boost verwenden, ABER ich verwende es so, wie es die libstdc ++ irgendwann haben wird. Ja, ein eigenes Projekt zu beginnen und gleich zu Beginn mit einem Standard (...) zu beginnen, ist sehr hilfreich bei der Wartung, Entwicklung und allem, was mit dem Projekt zu tun hat!

Bearbeiten:
Nun, da ich Zeit habe, nur etwas zu klären. Ich glaube nicht, dass es eine gute Idee ist, absichtlich und spezifischer einen Namen einer Klasse / des anderen in der STL zu verwenden. Die Zeichenfolge ist die Ausnahme (ignorieren Sie die erste, obige oder zweite hier, Wortspiel, wenn Sie müssen) für mich, da mir die Idee von 'String' nicht gefallen hat. Wie es ist, bin ich immer noch sehr stark auf C und auf C ++ ausgerichtet. Sparsame Details, vieles von dem, woran ich arbeite, passt zu C mehr (aber es war eine gute Übung und eine gute Möglichkeit, mich dazu zu bringen, eine andere Sprache zu lernen und B. nicht weniger gegen Objekt / Klassen / etc zu voreingenommen sein, was vielleicht besser gesagt wird als weniger geschlossen, weniger arrogant, eher akzeptabel.). Aber was ist nützlich, was einige bereits vorgeschlagen haben? Ich benutze wirklich list (es ist ziemlich allgemein, oder?)sort (dasselbe), um zwei zu nennen, die einen Namenskonflikt verursachen würden, wenn ich dies tun würdeusing namespace std;Daher ziehe ich es vor, spezifisch zu sein, die Kontrolle zu haben und zu wissen, dass ich, wenn ich beabsichtige, es als Standardgebrauch zu verwenden, es angeben muss. Einfach gesagt: keine Annahme erlaubt.

Und wie man Boosts Regex zu einem Teil macht std. Ich mache das für die zukünftige Integration und wieder, ich gebe völlig zu, dass dies eine Befangenheit ist - ich denke nicht, dass es so hässlich ist wie in der boost::regex:: ...Tat, das ist eine andere Sache für mich. Es gibt viele Dinge in C ++, die ich in Looks und Methoden noch nicht vollständig akzeptieren muss (ein anderes Beispiel: Variadic Templates vs. Vargs [obwohl ich zugeben muss, dass Variadic Templates sehr nützlich sind!]). Selbst die, die ich akzeptiere, waren schwierig UND ich habe immer noch Probleme mit ihnen.


Mit nicht qualifizierten importierten Bezeichnern benötigen Sie externe Suchtools wie grep , um herauszufinden, wo Bezeichner deklariert werden. Dies erschwert die Begründung der Programmkorrektheit.


Um Ihre Frage zu beantworten, betrachte ich sie praktisch so: Viele Programmierer (nicht alle) rufen den Namespace std auf. Daher sollte man sich angewöhnen, KEINE Dinge zu verwenden, die den Namen des Namensraums std beeinflussen oder verwenden. Das ist sehr viel gegeben, aber nicht so sehr im Vergleich zu der Anzahl möglicher kohärenter Wörter und Pseudonyme, die streng genommen werden können.

Ich meine wirklich ... zu sagen: "Verlassen Sie sich nicht darauf, dass diese Person anwesend ist", bedeutet, dass Sie sich darauf verlassen müssen, dass es NICHT anwesend ist. Sie werden ständig Probleme haben, Code-Schnipsel auszuleihen und sie ständig zu reparieren. Halten Sie einfach Ihre benutzerdefinierten und geliehenen Sachen in einem begrenzten Umfang, wie sie sein sollten, und sparen Sie SEHR mit Globals (ehrlich gesagt, sollten Globals fast immer ein letzter Ausweg für Zwecke des "Kompilierens jetzt, Vernunft später" sein). Ich glaube wirklich, dass dies ein schlechter Ratschlag von Ihrem Lehrer ist, da die Verwendung von std sowohl für "cout" als auch für "std :: cout" funktioniert, aber die Verwendung von std nur für "std :: cout". Sie werden nicht immer das Glück haben, Ihren eigenen Code zu schreiben.

HINWEIS: Konzentrieren Sie sich nicht zu sehr auf Effizienzprobleme, bis Sie tatsächlich etwas über die Funktionsweise von Compilern erfahren. Mit etwas Erfahrung beim Codieren müssen Sie nicht viel über sie lernen, bevor Sie erkennen, wie gut sie guten Code in etwas einfaches verallgemeinern können. Alles so einfach, als ob Sie das Ganze in C geschrieben hätten. Guter Code ist nur so komplex, wie er sein muss.


Wenn Sie aus meiner Erfahrung mehrere Bibliotheken haben, die beispielsweise verwenden cout, aber zu einem anderen Zweck können Sie das falsche verwenden cout.

Wenn ich in zum Beispiel geben, using namespace std;und , using namespace otherlib;und geben Sie nur cout (was sowohl sein geschieht), und nicht std::cout(oder 'otherlib::cout'), könnte man die falsche Verwendung und Fehlermeldungen erhalten, ist es viel effektiver und effizienter zu nutzen std::cout.





c++-faq