Verwenden Sie `using` in C ++ oder vermeiden Sie es?

17

Wie soll ich generell vorgehen usingund warum? Ist es situationsabhängig (zB Header, der #included sein wird, vs. Quelldatei, der nicht sein wird)?

Auch sollte ich lieber ::std::oder std::?

  1. Namespace-Ebene using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Vollständig explizit sein:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Namespace-Ebene mit Deklarationen:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. Funktionslokale using-Deklarationen:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Funktionslokal using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Etwas anderes?

Dies setzt Pre-C ++ 14 voraus und somit keine Return-Type-Deduktion mit auto.

Mehrdad
quelle
2
Einen Anfang finden Sie unter stackoverflow.com/questions/1265039/using-std-namespace .
AProgrammer
@AProgrammer: Ah, danke für den Link, der einen Teil meiner Frage beantwortet. :) immer noch fragen , über ::std::vs. std::though.
Mehrdad
4
Ich benutze zwar stdohne Sekunde. Jemand, der einen std-Namespace definiert, fragt nach Problemen (und versucht wahrscheinlich, die Vorteile zu nutzen, die die meisten Leute nutzen stdund nicht ::std).
Programmierer

Antworten:

25

Vermeiden Sie die Verwendung usingin Headern, da dies den Zweck von Namespaces verletzt.

Es ist in Ordnung, es in Quelldateien zu verwenden, aber ich würde es in einigen Fällen (zum Beispiel using std) immer noch vermeiden .

Wenn Sie jedoch verschachtelte Namespaces haben, ist dies in Ordnung:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A
BЈовић
quelle
6
+1 Es ist erstaunlich, wie viele Tutorials und College-Kurse Ihnen nur sagen, dass Sie das usingSchlüsselwort verwenden sollen, ohne eine gründliche Erklärung zu haben, warum Namespaces zu Beginn verwendet werden.
Jeffrey Sweeney
Die Leute wollen mit Iostreams, Strings usw. weitermachen. Sie möchten nicht jedes Mal std :: eingeben müssen, wenn sie etwas verwenden möchten, oder sich ein weiteres Stück Boilerplate merken müssen, das vor ihren Code gestellt werden muss, was zu weniger als nützlichen Fehlern führt, wenn sie es vergessen . :(
Colen
Würde so etwas wie typedef std :: string sstring; eine Alternative sein?
Giorgio
1
@Colen: Diese armen Seelen können using std::coutund Freunde, aber es ist nicht so, dass coutes schon ein schrecklich langer Name ist.
Benjamin Bannier
1
Wenn Sie an Ihrem ersten Tag in "meinem ersten C ++ - Kurs" ein Student sind, kann dies zu Syntaxfehlern führen, die Sie nicht verstehen. Es fällt uns leicht, herauszufinden, weil wir erfahrene Programmierer sind, aber wenn Sie versuchen, die Sprache zu lernen, ist es eine weitere Sache, sich Sorgen zu machen, die Sie nicht brauchen.
Colen
11

Wenn Sie eine using-Anweisung in eine Quelldatei einfügen, müssen Sie nur die erforderlichen Informationen eingeben. Zum Beispiel:

using std::string;
using std::ostringstream;

Das Problem hierbei ist, dass, wenn Sie dies tun

using namespace std;

Sie ziehen JEDES EINZELNE von STD in den globalen Namespace. Dies führt zu sehr interessanten Fehlermeldungen, wenn Sie versehentlich einen Namen in Ihrem Code verwenden, der mit einem übereinstimmt, den Sie in std. Wenn Sie nur das gewünschte Material einlesen, haben Sie dieses Problem nicht (oder genauer gesagt, der nächste Programmierer, der an Ihrem Code arbeitet, wird dieses Problem nicht haben).

Michael Kohne
quelle
Alternativ können Sie using namespacenur in einem Funktionsumfang das Problem vermeiden.
Tamás Szelei
2
@fish - Tatsächlich vermeidet das Verwenden von Namespace im Funktionsumfang nicht das Problem, sondern begrenzt nur den Bereich, in dem Probleme auftreten können. Und wenn Sie am Ende in jeder Funktion "using namespace" setzen, ist das nicht viel anders, als es nur global zu tun.
Michael Kohne
In C ++ können zwar Typen auf Funktionsebene deklariert werden, dies ist jedoch keine alltägliche Sache. Ansonsten sind die möglichen Namenskonflikte in der Compiler-Ausgabe leicht zu erkennen (aber Sie haben Recht, dass dies sie nicht verhindert).
Tamás Szelei
2

Verwenden Sie VJovic zufolge nicht usingin einer Header-Datei. usingin einer Headerdatei wirkt sich auf die aktuelle Kompilierungseinheit (die CPP-Datei) in einer Weise aus, die die Quelldatei möglicherweise nicht erwartet.

using namespaceist auch in einer Quelldatei zu vermeiden. Dies bringt jedes Symbol in den gleichen Bereich wie die Quelldatei. Den Lesern wird klarer, was Sie tun, wenn Sie bestimmte Symbole aus dem Namespace verwenden.

Bill Door
quelle
2
Aus praktischen using namespace JoystickModuleGründen würde ich, sofern Ihr Code nicht häufig verwendete Namen überschreibt, lieber am Anfang einer CPP-Datei als JoystickModule::an jedes Objekt angehängt sehen.
Alex P
@AlexP: Genau so mache ich es. Eine usingAnweisung für meinen eigenen Namespace, an dem ich gerade arbeite, und alles andere bleibt in Namespaces.
Benjamin Kloster
Ich sollte auf "bestimmte Symbole aus dem Namespace verwenden" näher eingehen. Anstatt jedem Symbol bei jeder Verwendung ein Präfix voranzustellen, was der Lesbarkeit nicht förderlich ist, bevorzuge ich die explizite Symbolerhöhung. using SomeNameSpace::SomeSymbol. Dadurch wird vermieden, dass jedes Symbol aus dem Namespace in den aktuellen Bereich verschoben wird.
Bill Door
0

Schreiben usingin Headern ist der beste Weg, um alle Arten von bösen und unmöglich zu debuggenden Fehlern zu erstellen . Mach das nicht .

Das Schreiben using namespace XYZin der Quelldatei ist etwas besser, kann aber dennoch unzählige Kopfschmerzen verursachen. Auf sichere Weise können Sie explizit angeben, was Sie verwenden, z using Foo::Bar.

Angenommen, Sie haben Bar.cpp mit folgendem Inhalt:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

Die Funktion funktionierte einwandfrei, bis sich eines Tages - scheinbar ohne Codeänderungen in relevanten Klassen - ihr Verhalten änderte: Plötzlich currentIndexscheint es immer um eins zu gehen . Wenn Sie die letzten Änderungen durchgehen, werden Sie feststellen, dass sich auch aus der Ferne keine Änderungen am Code ergeben.

Schließlich entdecken Sie die Ursache:
Sie schließen (indirekt) Foo.hirgendwo ein. In den Dateien für den Foo-Namespace wurde eine neue Funktion hinzugefügt:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Welches ist eine eindeutig bessere Übereinstimmung increment(int)als Ihre Funktion increment(double)- so wird Foo::increment()Funktion jetzt Bar::someFunction()stattdessen von aufgerufen . Hoppla.

(Und wenn Sie usingin Überschriften schreiben würden , using namespace Foodie sich sehr gut irgendwo in Ihrem Include-Baum befinden könnten ...)

So ... Do nicht schreibt jede usingin Header und auch das Schreiben vorsichtig sein , using namespacein Quelldateien.

CharonX
quelle