IOW: Gibt es einen Grund, einen dem anderen vorzuziehen?
Referenzen sind natürlich wertvoll, aber ich komme aus C, wo Zeiger überall sind. Man muss zuerst mit Zeigern vertraut sein, um den Wert von Referenzen zu verstehen.
– Jay D
8. Mai 2012 um 19:43 Uhr
Wie passt das zu einem Ziel wie referentielle Transparenz aus der funktionalen Programmierung? Was ist, wenn Sie möchten, dass Funktionen immer neue Objekte zurückgeben und den Status niemals intern ändern, insbesondere nicht von Variablen, die an die Funktion übergeben werden? Gibt es eine Möglichkeit, dieses Konzept immer noch mit Zeigern und Referenzen in einer Sprache wie C++ zu verwenden. (Beachten Sie, ich gehe davon aus, dass jemand bereits das Ziel der referenziellen Transparenz hat. Ich bin nicht daran interessiert, darüber zu sprechen, ob es ein gutes Ziel ist oder nicht.)
– Ely
30. September 2013 um 17:31 Uhr
Referenzen bevorzugen. Benutzerhinweise, wenn Sie keine Wahl haben.
– Ferruccio
5. Juli 2014 um 13:14 Uhr
Nils Pipenbrink
Meine Faustregel lautet:
Verwenden Sie Zeiger, wenn Sie mit ihnen Zeigerarithmetik durchführen wollen (zB die Zeigeradresse erhöhen, um ein Array zu durchlaufen) oder wenn Sie jemals einen NULL-Zeiger übergeben müssen.
Verwenden Sie ansonsten Referenzen.
Ausgezeichneter Punkt bezüglich eines Zeigers, der NULL ist. Wenn Sie einen Zeigerparameter haben, müssen Sie entweder explizit prüfen, dass er nicht NULL ist, oder alle Verwendungen der Funktion durchsuchen, um sicherzustellen, dass er niemals NULL ist. Bei Referenzen entfällt dieser Aufwand.
– Richard Corden
22. September 2008 um 11:10 Uhr
Erklären Sie, was Sie unter Arithmetik verstehen. Ein neuer Benutzer versteht möglicherweise nicht, dass Sie anpassen möchten, worauf der Zeiger zeigt.
– Martin York
22. September 2008 um 16:30 Uhr
Martin, mit Arithmetik meine ich, dass Sie einen Zeiger auf eine Struktur übergeben, aber wissen, dass es sich nicht um eine einfache Struktur handelt, sondern um ein Array davon. In diesem Fall können Sie es entweder mit indizieren [] oder rechnen Sie mit ++/– auf dem Zeiger. Das ist der Unterschied in Kürze.
– Nils Pipenbrinck
25. November 2008 um 20:35 Uhr
Martin, das geht nur mit Zeigern direkt. Nicht mit Referenzen. Sicher, Sie können einen Zeiger auf eine Referenz nehmen und in der Praxis dasselbe tun, aber wenn Sie dies tun, enden Sie mit sehr schmutzigem Code.
– Nils Pipenbrinck
25. November 2008 um 20:38 Uhr
Was ist mit Polymorphismus (zB Base* b = new Derived())? Dies scheint ein Fall zu sein, der ohne Hinweise nicht behandelt werden kann.
– Chris Redford
7. März 2013 um 19:25 Uhr
Johann Gell
Ich denke wirklich, dass Sie davon profitieren werden, wenn Sie die folgenden Codierungsrichtlinien für Funktionsaufrufe festlegen:
Wie an allen anderen Orten immer sein const-Korrekt.
Hinweis: Das bedeutet unter anderem, dass nur out-Werte (siehe Punkt 3) und als Wert übergebene Werte (siehe Punkt 4) fehlen können const Bezeichner.
Übergeben Sie einen Wert nur per Zeiger, wenn der Wert 0/NULL im aktuellen Kontext eine gültige Eingabe ist.
Begründung 1: Als ein AnruferSie sehen das, was auch immer Sie passieren muss sein in einem brauchbaren Zustand.
Begründung 2: Als namensdu weißt, was auch immer reinkommt ist in einem brauchbaren Zustand. Daher muss für diesen Wert keine NULL-Prüfung oder Fehlerbehandlung durchgeführt werden.
Begründung 3: Begründung 1 und 2 werden sein Compiler erzwungen. Fangen Sie Fehler immer zur Kompilierzeit ab, wenn Sie können.
Wenn ein Funktionsargument ein Out-Wert ist, übergeben Sie es als Referenz.
Begründung: Wir wollen Punkt 2 nicht brechen …
Wählen Sie “Pass by Value” gegenüber “Pass by Const Reference” nur dann, wenn der Wert ein POD (Plain Old Datastructure) oder klein genug (speichermäßig) oder auf andere Weise billig genug (zeitlich) zum Kopieren ist.
Begründung: Vermeiden Sie unnötige Kopien.
Notiz: klein genug und billig genug sind nicht absolut messbar.
Es fehlt die Richtlinie, wenn: … “wann const & verwendet werden soll” … Die Richtlinie 2 sollte geschrieben werden “für [in] Werte, Zeiger nur übergeben, wenn NULL gültig ist. Verwenden Sie andernfalls const reference (oder für “kleine” Objekte copy) oder reference, falls es sich um eine handelt [out] Wert. Ich beobachte diesen Beitrag, um möglicherweise +1 hinzuzufügen.
– Paercebal
22. September 2008 um 11:54 Uhr
Punkt 1 deckt den von Ihnen beschriebenen Fall ab.
– Johann Gerell
22. September 2008 um 13:14 Uhr
Es ist ein bisschen schwierig, einen Out-Parameter als Referenz zu übergeben, wenn er nicht standardmäßig konstruierbar ist. Das kommt in meinem Code ziemlich häufig vor – der einzige Grund dafür, dass eine Funktion dieses Out-Objekt erstellt, ist, dass es nicht trivial ist.
– MSalter
22. September 2008 um 15:02 Uhr
@MSalters: Wenn Sie den Speicher innerhalb der Funktion zuweisen (was Sie meiner Meinung nach meinen), warum geben Sie dann nicht einfach einen Zeiger auf den zugewiesenen Speicher zurück?
– Kleist
16. Februar 2011 um 9:27 Uhr
@Kleist: Im Namen von @MSalters gibt es viele mögliche Gründe. Einer davon ist, dass Sie möglicherweise bereits Speicher zugewiesen haben, um ihn zu füllen, wie bei einer voreingestellten Größe std::vector<>.
– Johann Gerell
16. Februar 2011 um 10:28 Uhr
Aaron N. Tubbs
Das ist letztlich subjektiv. Die bisherige Diskussion ist nützlich, aber ich glaube nicht, dass es darauf eine richtige oder entscheidende Antwort gibt. Vieles hängt von den Stilrichtlinien und Ihren aktuellen Bedürfnissen ab.
Während es bei einem Zeiger einige unterschiedliche Fähigkeiten gibt (ob etwas NULL sein kann oder nicht), besteht der größte praktische Unterschied für einen Ausgabeparameter in der reinen Syntax. Googles C++ Style Guide (https://google.github.io/styleguide/cppguide.html#Reference_Arguments) verlangt beispielsweise nur Zeiger für Ausgabeparameter und erlaubt nur Verweise, die konstant sind. Der Grund liegt in der Lesbarkeit: Etwas mit Wertesyntax sollte keine semantische Zeigerbedeutung haben. Ich behaupte nicht, dass dies notwendigerweise richtig oder falsch ist, aber ich denke, der Punkt hier ist, dass es eine Frage des Stils ist, nicht der Korrektheit.
Was bedeutet es, dass Referenzen eine Wertsyntax, aber eine semantische Zeigerbedeutung haben?
– Eric Andrew Lewis
16. August 2015 um 13:43 Uhr
Es sieht so aus, als würden Sie eine Kopie übergeben, da der Teil “Pass by Reference” nur aus der Funktionsdefinition (Wertsyntax) ersichtlich ist, aber Sie kopieren nicht den Wert, den Sie übergeben, Sie übergeben im Wesentlichen einen Zeiger unter der Haube, was dies ermöglicht die Funktion, um Ihren Wert zu ändern.
– phant0m
19. Mai 2016 um 10:35 Uhr
Man sollte nicht vergessen, dass der Google C++ Styleguide sehr verabscheut wird.
– Deduplizierer
20. Dezember 2018 um 0:54 Uhr
Zeiger
Ein Zeiger ist eine Variable, die eine Speicheradresse enthält.
Eine Zeigerdeklaration besteht aus einem Basistyp, einem * und dem Variablennamen.
Ein Zeiger kann während der Lebensdauer auf eine beliebige Anzahl von Variablen zeigen
Ein Zeiger, der derzeit nicht auf einen gültigen Speicherplatz zeigt, erhält den Wert null (was null ist).
Das & ist ein unärer Operator, der die Speicheradresse seines Operanden zurückgibt.
Dereferenzierungsoperator
int nVar = 7;
int* ptrVar = &nVar;
int nVar2 = *ptrVar;
wird verwendet, um auf den Wert zuzugreifen, der in der Variablen gespeichert ist, auf die der Zeiger zeigt.
Referenz
Eine Referenz (&) ist wie ein Alias für eine vorhandene Variable.
Eine Referenz (&) ist wie ein konstanter Zeiger, der automatisch dereferenziert wird.
Es wird normalerweise für Funktionsargumentlisten und Funktionsrückgabewerte verwendet.
Eine Referenz muss initialisiert werden, wenn sie erstellt wird.
Sobald eine Referenz auf ein Objekt initialisiert wurde, kann sie nicht geändert werden, um auf ein anderes Objekt zu verweisen.
Sie können keine NULL-Referenzen haben.
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
Geben Sie hier die Bildbeschreibung ein
Sie sollten einen Zeiger übergeben, wenn Sie den Wert der Variablen ändern möchten. Obwohl das Übergeben einer Referenz oder eines Zeigers technisch gesehen dasselbe ist, ist das Übergeben eines Zeigers in Ihrem Anwendungsfall besser lesbar, da er die Tatsache „ankündigt“, dass der Wert durch die Funktion geändert wird.
Wenn Sie den Richtlinien von Johann Gerell folgen, kündigt eine nicht konstante Referenz auch eine veränderbare Variable an, sodass der Zeiger hier diesen Vorteil nicht hat.
– Alexander Kondratsky
19. Juli 2011 um 13:39 Uhr @AlexanderKondratskiy: Sie verfehlen den Punkt … Sie können nicht sofort sehen am Aufrufort const ob die aufgerufene Funktion einen Parameter als akzeptiertconst oder nicht- &x Referenz, aber Sie können sehen, ob der Parameter ala übergeben wurde xvs. const , und verwenden Sie diese Konvention, um zu codieren, ob der Parameter geändert werden kann. (Das heißt, es gibt Zeiten, in denen Sie eine bestehen möchten
Zeiger, also ist die Konvention nur ein Hinweis. Es ist weniger gefährlich zu vermuten, dass etwas geändert werden könnte, wenn es nicht sein wird, als zu glauben, dass es nicht sein wird, wenn es sein wird ….)
// 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);
}
. Dadurch können Sie optionale Werte als Referenz und auch als Rückgabewert übergeben.
Wenn Sie den Richtlinien von Johann Gerell folgen, kündigt eine nicht konstante Referenz auch eine veränderbare Variable an, sodass der Zeiger hier diesen Vorteil nicht hat.
– Alexander Kondratsky
19. Juli 2011 um 13:39 Uhr @AlexanderKondratskiy: Sie verfehlen den Punkt … Sie können nicht sofort sehen am Aufrufort const ob die aufgerufene Funktion einen Parameter als akzeptiertconst oder nicht- &x Referenz, aber Sie können sehen, ob der Parameter ala übergeben wurde xvs. const , und verwenden Sie diese Konvention, um zu codieren, ob der Parameter geändert werden kann. (Das heißt, es gibt Zeiten, in denen Sie eine bestehen möchten
Zeiger, also ist die Konvention nur ein Hinweis. Es ist weniger gefährlich zu vermuten, dass etwas geändert werden könnte, wenn es nicht sein wird, als zu glauben, dass es nicht sein wird, wenn es sein wird ….)
Referenzen sind natürlich wertvoll, aber ich komme aus C, wo Zeiger überall sind. Man muss zuerst mit Zeigern vertraut sein, um den Wert von Referenzen zu verstehen.
– Jay D
8. Mai 2012 um 19:43 Uhr
Wie passt das zu einem Ziel wie referentielle Transparenz aus der funktionalen Programmierung? Was ist, wenn Sie möchten, dass Funktionen immer neue Objekte zurückgeben und den Status niemals intern ändern, insbesondere nicht von Variablen, die an die Funktion übergeben werden? Gibt es eine Möglichkeit, dieses Konzept immer noch mit Zeigern und Referenzen in einer Sprache wie C++ zu verwenden. (Beachten Sie, ich gehe davon aus, dass jemand bereits das Ziel der referenziellen Transparenz hat. Ich bin nicht daran interessiert, darüber zu sprechen, ob es ein gutes Ziel ist oder nicht.)
– Ely
30. September 2013 um 17:31 Uhr
Referenzen bevorzugen. Benutzerhinweise, wenn Sie keine Wahl haben.
– Ferruccio
5. Juli 2014 um 13:14 Uhr