it-swarm.com.de

Zeiger vs. Referenz

Was wäre eine bessere Übung, wenn Sie einer Funktion die ursprüngliche Variable zuweisen, mit der Sie arbeiten möchten:

unsigned long x = 4;

void func1(unsigned long& val) {
     val = 5;            
}
func1(x);

oder:

void func2(unsigned long* val) {
     *val = 5;
}
func2(&x);

IOW: Gibt es einen Grund, sich gegenseitig auszusuchen?

247
Jack Reza

Meine Faustregel lautet:

Verwenden Sie Zeiger, wenn Sie mit ihnen eine Zeigerarithmetik durchführen möchten (z. B. die Zeigeradresse erhöhen, um ein Array zu durchlaufen) oder wenn Sie jemals einen NULL-Zeiger übergeben müssen.

Verwenden Sie Referenzen ansonsten.

275

Ich denke wirklich, dass Sie von der Einrichtung der folgenden Funktionsaufruf-Kodierungsrichtlinien profitieren werden:

  1. Seien Sie wie an allen anderen Orten immer const- korrekt.

    • Hinweis: Dies bedeutet unter anderem, dass nur bei out-Werten (siehe Punkt 3) und Werten, die als Wert übergeben werden (siehe Punkt 4), der const -Spezifizierer fehlen kann.
  2. Übergeben Sie einen Wert nur dann als Zeiger, wenn der Wert 0/NULL im aktuellen Kontext eine gültige Eingabe ist.

    • Begründung 1: Als Anrufer sehen Sie, dass alles, was Sie übergeben muss sein in einem verwendbaren Zustand ist.

    • Begründung 2: Wie genannt , wissen Sie, dass alles, was in ist kommt, in einem verwendbaren Zustand ist. Daher muss für diesen Wert keine NULL-Prüfung oder Fehlerbehandlung durchgeführt werden.

    • Begründung 3: Rationales 1 und 2 werden Compiler erzwungen. Erfassen Sie Fehler immer zur Kompilierungszeit, wenn Sie können.

  3. Wenn ein Funktionsargument ein out-value ist, übergeben Sie es als Referenz.

    • Begründung: Wir wollen Punkt 2 nicht brechen ...
  4. Wählen Sie "Übergabe nach Wert" gegenüber "Übergabe nach Konstantenreferenz" nur, wenn der Wert ein POD ( Plain old Datastructure ) oder klein genug (speicherbasiert) oder auf andere Weise billig genug (zeitbasiert) ist ) Kopieren.

    • Begründung: Vermeiden Sie unnötige Kopien.
    • Hinweis: klein genug und billig genug sind keine absoluten Messgrößen.
71
Johann Gerell

Dies ist letztendlich subjektiv. Die bisherige Diskussion ist nützlich, aber ich glaube nicht, dass es eine richtige oder entscheidende Antwort darauf gibt. Vieles wird von den Stilrichtlinien und Ihren Bedürfnissen zu der Zeit abhängen.

Während es bei einem Zeiger einige verschiedene Funktionen gibt (unabhängig davon, ob etwas NULL sein kann oder nicht), besteht der größte praktische Unterschied für einen Ausgabeparameter in der reinen Syntax. In Googles C++ Style Guide ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ) sind beispielsweise nur Zeiger für Ausgabeparameter und nur Verweise zulässig, die const sind. Die Argumentation ist eine der Lesbarkeit: Etwas mit Wertsyntax sollte keine semantische Bedeutung für Zeiger haben. Ich behaupte nicht, dass dies notwendigerweise richtig oder falsch ist, aber ich denke, der Punkt hier ist, dass es um Stil geht, nicht um Korrektheit.

24
Aaron N. Tubbs

Sie sollten einen Zeiger übergeben, wenn Sie den Wert der Variablen ändern möchten. Obwohl die technische Übergabe einer Referenz oder eines Zeigers identisch ist, ist die Übergabe eines Zeigers in Ihrem Anwendungsfall besser lesbar, da die Tatsache "angekündigt" wird, dass der Wert von der Funktion geändert wird.

7
Max Caceres

Wenn Sie einen Parameter haben, bei dem Sie möglicherweise das Fehlen eines Werts angeben müssen, ist es üblich, den Parameter als Zeigerwert zu definieren und NULL zu übergeben.

In den meisten Fällen (aus Sicherheitsgründen) ist die Verwendung von boost :: optional eine bessere Lösung. Auf diese Weise können Sie optionale Werte als Referenz und als Rückgabewert übergeben.

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}
5
Kiley Hykawy

Zeiger

  • Ein Zeiger ist eine Variable, die eine Speicheradresse enthält.
  • Eine Zeigerdeklaration besteht aus einem Basistyp, einem * und dem Variablennamen.
  • Ein Zeiger kann auf eine beliebige Anzahl von Variablen im Leben zeigen
  • Ein Zeiger, der derzeit nicht auf einen gültigen Speicherort verweist, erhält den Wert null (der null ist).

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • Das & ist ein unärer Operator, der die Speicheradresse seines Operanden zurückgibt.

  • Der Dereferenzierungsoperator (*) wird verwendet, um auf den Wert zuzugreifen, der in der Variablen gespeichert ist, auf die der Zeiger zeigt.

       int nVar = 7;
       int* ptrVar = &nVar;
       int nVar2 = *ptrVar;
    

Referenz

  • Ein Verweis (&) ist wie ein Alias ​​auf eine vorhandene Variable.

  • Ein Verweis (&) ist wie ein konstanter Zeiger, der automatisch dereferenziert wird.

  • Es wird normalerweise für Funktionsargumentlisten und Funktionsrückgabewerte verwendet.

  • Eine Referenz muss beim Erstellen initialisiert werden.

  • Sobald eine Referenz auf ein Objekt initialisiert wurde, kann sie nicht mehr geändert werden, um auf ein anderes Objekt zu verweisen.

  • Sie können keine NULL-Referenzen haben.

  • Eine const-Referenz kann auf eine const int verweisen. Dies geschieht mit einer temporären Variablen mit dem Wert der Konstante

    int i = 3;    //integer declaration
    int * pi = &i;    //pi points to the integer i
    int& ri = i;    //ri is refers to integer i – creation of reference and initialization
    

enter image description here

enter image description here

4
Saurabh Raoot

Verwenden Sie eine Referenz, wenn Sie können, und einen Zeiger, wenn Sie müssen. Von C++ - FAQ: "Wann sollte ich Verweise verwenden und wann sollten Zeiger verwendet werden?"

4
RezaPlusPlus

Betrachten Sie das Schlüsselwort out von C #. Der Compiler fordert den Aufrufer einer Methode auf, das out-Schlüsselwort auf alle out-Argumente anzuwenden, obwohl er bereits weiß, ob dies der Fall ist. Dies soll die Lesbarkeit verbessern. Obwohl ich bei modernen IDEs eher der Meinung bin, dass dies ein Job zum Hervorheben von Syntax (oder Semantik) ist.

3

Zeiger:

  • Kann nullptr (oder NULL) zugewiesen werden.
  • Auf der Aufrufseite müssen Sie & Verwenden, wenn Ihr Typ selbst kein Zeiger ist, und explizit angeben, dass Sie Ihr Objekt ändern.
  • Zeiger können zurückgebunden werden.

Verweise:

  • Kann nicht Null sein.
  • Einmal gebunden, kann nicht geändert werden.
  • Anrufer müssen nicht explizit & Verwenden. Dies wird manchmal als schlecht angesehen, da Sie zur Implementierung der Funktion gehen müssen, um festzustellen, ob Ihr Parameter geändert wurde.
2
Germán Diago

Geben Sie einen konstanten Verweis ein, es sei denn, Sie möchten den Inhalt, den Sie weitergeben, aus einem bestimmten Grund ändern/beibehalten.

Dies ist in den meisten Fällen die effizienteste Methode.

Stellen Sie sicher, dass Sie const für jeden Parameter verwenden, den Sie nicht ändern möchten, da dies Sie nicht nur davor schützt, etwas Dummes in der Funktion zu tun, sondern auch anderen Benutzern einen guten Hinweis gibt, was die Funktion mit den übergebenen Werten macht. Dazu gehört das Erstellen einer Zeigerkonstante, wenn Sie nur das ändern möchten, auf das verwiesen wird ...

2
NotJarvis

Eine Referenz ähnelt einem Zeiger, außer dass Sie kein Präfix pref verwenden müssen, um auf den Wert zuzugreifen, auf den sich die Referenz bezieht. Es kann auch nicht darauf verwiesen werden, dass nach seiner Initialisierung auf ein anderes Objekt verwiesen wird.

Referenzen sind besonders nützlich für die Angabe von Funktionsargumenten.

weitere Informationen finden Sie unter "A Tour of C++" von "Bjarne Stroustrup" (2014), Seiten 11-12

0
amirfg