Wann wird in C++ als Referenz und wann als Zeiger übergeben?

Lesezeit: 7 Minuten

Benutzer-Avatar
Benutzer855

Häufige Situationen:

  1. std::string an eine Funktion übergeben foo(std::string*) oder foo(std::string&);
  2. Übergabe von tr1::shared_ptr an eine Funktion foo(tr1::shared_ptr* ptr) oder foo(tr1::shared_ptr& ptr);

Im Allgemeinen, was ist eine gute Praxis. Ich bin immer verwirrt. Alles als Referenzen zu übergeben scheint zunächst konsistent, es ist jedoch nicht möglich, Literale als Referenzen oder NULLs als Referenzen zu übergeben.

Ebenso scheint es gut zu sein, alles als Zeiger zu haben, aber dann muss ich mir Sorgen machen, dass Zeiger auf NULL zeigen und am Anfang dieser Funktion nach diesen Bedingungen suchen.

Finden Sie den folgenden Ausschnitt gut?

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <tr1/memory>
#include <algorithm>
using namespace std;
using namespace std::tr1;

int main(){
        map<string, shared_ptr<vector<string> > > adjacencyMap;
        vector<string>* myFriends = new vector<string>();
        myFriends->push_back(string("a"));
        myFriends->push_back(string("v"));
        myFriends->push_back(string("g"));
        adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends);
        return 0;
}

Danke Ajay

  • foo(tr1::shared_ptr<string>* ptr) das scheint meiner Meinung nach aus der Perspektive von gutem Design einfach sehr falsch zu sein. kennst du dich mit ständigen referenzen aus?

    – Irgendein Korn

    31. August 2010 um 20:55 Uhr


  • Warum setzen Sie nicht myFriends sofort in einen Smart Pointer?

    – GManNickG

    31. August 2010 um 20:55 Uhr

  • Ich denke, dies ist ein Duplikat von How to pass objects to functions in C++?, wo ich die allgemeine Frage bereits beantwortet habe.

    – sbi

    31. August 2010 um 20:59 Uhr


  • Sie können auch NICHT a verwenden shared_ptr (oder ein new), siehe meine Antwort …

    – Matthias M.

    1. September 2010 um 7:00 Uhr

  • mögliches Duplikat von Wenn Pass-by-Pointer in C++ der Pass-by-Referenz vorgezogen wird?

    – aussen

    21. Januar 2012 um 0:22 Uhr

Referenzen sind einfacher zu finden.

Ist Ihr Problem mit Literalen, dass Sie keine konstanten Referenzen verwenden? Sie können ein temporäres (von einem Literal erzeugtes) nicht an eine nicht konstante Referenz binden, da es keinen Sinn macht, eine zu ändern. Sie können eine an eine const-Referenz binden.

Insbesondere, wenn ein Argument an eine Funktion übergeben wird und die Funktion es nicht ändern wird und es sich nicht um einen integrierten Typ handelt, übergeben Sie es als const-Referenz. Es funktioniert ähnlich wie Wertübergabe, außer dass es keinen Kopierkonstruktoraufruf erfordert.

Zeiger sind insofern nützlich, als sie einen garantiert ungültigen Wert haben, den Sie testen können. Manchmal ist das irrelevant, und manchmal ist es sehr wichtig. Natürlich können Sie ein Literal im Allgemeinen nicht per Zeiger übergeben, es sei denn (im Falle eines String-Literals) ist dies bereits der Fall.

Einige Codierungsstandards besagen, dass niemals eine nicht-konstante Referenz übergeben werden sollte, da sie zum Zeitpunkt des Aufrufs keinen Hinweis darauf gibt, dass das Argument durch die Funktion geändert werden könnte. In diesem Fall müssen Sie den Zeiger übergeben. Ich befürworte das nicht, zumal Programmiertools es immer einfacher machen, die Funktionssignatur zu erhalten, sodass Sie sehen können, ob eine Funktion ein Argument ändern könnte. Bei der Arbeit in einer Gruppe oder für ein Unternehmen ist Stilkonsistenz jedoch wichtiger als jedes einzelne Stilelement.

Eine gute Faustregel: „Verwenden Sie Referenzen, wenn Sie können, und Hinweise, wenn Sie müssen“.

In meinem vorherigen Job galt die Regel, dass Klartextangaben praktisch nie verwendet wurden. Stattdessen vereinbarten wir:

  • Pass by Value (für billig zu kopierende Objekte, alle Primitiven, kleine Werttypen, std::stringsehr kleine oder neu gezählte Zeichenfolgen)
  • Vorbeigehen const Referenz (für schreibgeschützten Zugriff auf große Objekte)
  • Übergeben Sie den Zeiger, wenn Sie Lese-/Schreibzugriff benötigen

Wenn alle diese Regeln befolgen, können Sie davon ausgehen, dass Parameter, die an Funktionen übergeben werden, nicht geändert werden, es sei denn, ihre Adresse wurde übernommen. Bei uns hat es funktioniert.

  • Warum std::string als Wert übergeben? Sollte per const-Referenz sein. Auch beim Lese-/Schreibzugriff sollten Sie standardmäßig per Referenz übergeben.

    – ronag

    31. August 2010 um 21:08 Uhr

  • Was ist, wenn Sie ein Primitiv innerhalb der Funktion ändern möchten? Wie erfüllt Punkt 1 diesen Fall?

    – Benutzer855

    31. August 2010 um 21:10 Uhr

  • +1, ziemlich vernünftig. @aja pass by pointer (Nummer 3) @ron Nummer 2 sagt es. “sollte” ist wirklich Geschmackssache

    – Irgendein Korn

    31. August 2010 um 21:15 Uhr

  • @ronag: Wenn Sie Zeichenfolgen übergeben, erwarten Sie normalerweise eine Pass-by-Value-Semantik. std::string behandelt kleine Strings speziell, um Kopien billig zu machen. Ich bin noch nie in einer Situation gelaufen, in der die Optimierung geholfen hat.

    Benutzer180326

    31. August 2010 um 21:27 Uhr

  • Ich ging davon aus, dass ich neu zählen würde, aber nach einigem Googeln scheint das aus der Mode gekommen zu sein. Ich werde bearbeiten.

    Benutzer180326

    31. August 2010 um 22:04 Uhr

Ich verstehe wirklich nicht, warum du dir diesen ganzen Ärger machst:

std::map < std::string, std::vector<std::string> > adjacencyMap;
std::vector<std::string>& sFriends = adjacencyMap["s"];
sFriends.push_back("a");
sFriends.push_back("v");
sFriends.push_back("g");

Warum mischst du dich ein shared_ptr hier ? Die Situation verlangt es jedenfalls nicht!

Sie können stöbern http://www.cplusplus.com/forum/beginner/3958/ für einige Einblicke. Auch nützlich: http://www.velocityreviews.com/forums/t284603-pointers-vs-references-a-question-on-style.html

Ich denke, es gibt keine “richtige” Antwort. Sie müssen die Vor- und Nachteile jedes Ansatzes unter Berücksichtigung des spezifischen Kontexts Ihres Projekts abwägen.

Ich persönlich bevorzuge Referenzen, aber ich empfehle trotzdem, diese Beiträge zu lesen und darüber nachzudenken.

Benutzer-Avatar
Zoli

Als allgemeine Faustregel sollten Sie immer versuchen, Parameter als Referenz an const zu übergeben. Das Übergeben von Zeigern kann zu Eigentumsproblemen sowie zu einer Reihe anderer Möglichkeiten für subtile Fehler führen.

Was ist der Zweck von NULL? Um einen ungültigen Zeiger/Objekt anzuzeigen. Wenn Sie ungültige Objekte an eine Funktion übergeben, brauchen Sie nur eine Methode, um die Gültigkeit eines Objekts zu überprüfen. Wie in:

void myfunc(const obj& myobj)
{
  if(myobj.valid())
    // DO SOMETHING
}

Primitive Typen, die Sie normalerweise sowieso als Wert übergeben möchten, da es so wenig Overhead gibt. Und dann würden Sie sowieso die meiste Zeit Literale verwenden. Für Saiten sollten Sie versuchen, zu verwenden std::string und bleib weg von const char* C-Style-Saiten so viel wie möglich. Wenn Sie C-Strings verwenden müssen, haben Sie natürlich keine andere Wahl, als Zeiger zu verwenden, aber alles in allem sollten Referenzen der richtige Weg sein.

Oh, und um wirklich ausnahmesicher zu sein, versuchen Sie Folgendes zu vermeiden:

vector<string>* myFriends = new vector<string>();
...
adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends);

Stattdessen tun:

shared_ptr<vector<string> > myFriends(new vector<string>());

Sehen Sie sich RAII und Ausnahmesicherheit an, um zu erfahren, warum dies die bevorzugte Methode ist.

Benutzer-Avatar
Ronag

Wahrscheinlich keine Antwort auf die Frage. Küss einfach.

int main()
{
        multimap<string, string> adjacencyMap;
        adjacencyMap.insert(std::make_pair("s", "a"));
        adjacencyMap.insert(std::make_pair("s", "v"));
        adjacencyMap.insert(std::make_pair("s", "g"));
        return 0;
}

  • Vielen Dank! Obwohl dies meine Frage nicht beantwortet, wusste ich nichts über Multimap. Und diese Verwendung scheint für diesen Fall sehr angemessen zu sein.

    – Benutzer855

    31. August 2010 um 21:27 Uhr

  • Beachten Sie nebenbei, dass es bei diesem Ansatz einen Speichertreffer zu geben scheint. Bei Verwendung einer Multimap wird derselbe Schlüssel wiederholt mehrfach gespeichert. Da Schlüssel in meinem Ansatz einzigartig sind, werden sie nur einmal gespeichert und der Speicherplatzverbrauch ist geringer. Irgendwelche Gedanken dazu?

    – Benutzer855

    31. August 2010 um 23:15 Uhr

  • Das ist implementierungsspezifisch. Ich glaube, die meisten Implementierungen speichern nur einen einmal eingefügten Schlüssel.

    – ronag

    1. September 2010 um 6:46 Uhr

  • Ich weiß nichts darüber, wenn Sie beim Iterieren einen Verweis auf ein Paar erhalten, wäre es schwierig, dies zurückzugeben, wenn sie die Optimierung implementieren, von der Sie sprechen.

    – Matthias M.

    1. September 2010 um 6:57 Uhr

1013360cookie-checkWann wird in C++ als Referenz und wann als Zeiger übergeben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy