Menu

C++-Funktionsparameter: Call by Value, Reference, Const

Wie Argumente in C++-Funktionen gelangen - Übergabe per Wert oder per Referenz, const-Referenzen für günstigen Nur-Lese-Zugriff, Standardargumente, Zeiger und die Kopierkosten-Fallen, die Programme unbemerkt verlangsamen.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Parameter vs. Argumente

Die Parameter einer Funktion sind die benannten Variablen in ihrer Definition; die Argumente sind die tatsächlichen Werte, die du ihr beim Aufruf übergibst. Die vorherige Seite hat gezeigt, wie man Funktionen definiert und aufruft - auf dieser Seite geht es darum, wie diese Werte tatsächlich hineingelangen, denn C++ bietet dir mehrere Möglichkeiten, und die Wahl wirkt sich sowohl auf die Korrektheit als auch auf die Geschwindigkeit aus.

Der Standard in C++ ist die Übergabe per Wert: Die Funktion erhält eine Kopie.

Innerhalb von addTen ist n eine eigenständige Variable, die aus score initialisiert wurde. Die Neuzuweisung von n berührt nur diese Kopie, sodass score zurück in main unverändert bleibt. Das ist sicher und vorhersehbar - die Funktion kann deine Daten nicht versehentlich überschreiben - und genau deshalb ist es der Standard.

Übergabe per Referenz: einer Funktion erlauben, den Aufrufer zu ändern

Manchmal willst du, dass die Funktion die Variable des Aufrufers ändert. Füge dem Parametertyp ein & hinzu, und er wird zu einer Referenz - einem Alias für das Original, keiner Kopie:

Der einzige Unterschied zum ersten Beispiel ist das &, aber jetzt sind n und score dasselbe Objekt. Das ist der Standardweg, um mehr als einen Wert „zurückzugeben" oder etwas an Ort und Stelle zu aktualisieren. Ein klassischer Anwendungsfall ist das Tauschen zweier Variablen:

Ohne das & würde swapValues zwei Kopien durcheinanderwürfeln, und main würde überhaupt keine Änderung sehen - ein sehr häufiger Anfängerfehler.

Const-Referenzen: günstiger, schreibgeschützter Zugriff

Die Übergabe per Wert kopiert das Argument. Für einen int kostet das nichts, aber einen großen string oder vector bei jedem Aufruf zu kopieren, ist echte, verschwendete Arbeit. Die Lösung ist eine const-Referenz (const T&): Du erhältst die Geschwindigkeit der Referenz (keine Kopie) plus ein vom Compiler erzwungenes Versprechen, das Argument nicht zu ändern.

Eine praktische Faustregel: Übergib kleine eingebaute Typen (int, double, char, bool, Zeiger) per Wert und übergib große Objekte, die du nur lesen musst, per const-Referenz. Reserviere ein einfaches, nicht-konstantes T& für die Fälle, in denen du das Objekt des Aufrufers tatsächlich ändern willst.

Eine subtile Falle: Ein einfaches int& n kann sich nicht an ein Temporary oder ein Literal binden. addTen(5) aus dem ersten Beispiel würde nicht kompilieren, wenn der Parameter int& wäre, weil 5 keine Variable ist, für die du einen Alias erstellen kannst. Ein const int& kann sich an 5 binden, was ein weiterer Grund ist, warum const-Referenzen so weit verbreitet sind.

Standardargumente

Du kannst einem Parameter einen Ersatzwert geben, sodass Aufrufer ihn weglassen dürfen. Fehlt das Argument, wird der Standardwert verwendet:

Zwei Regeln bringen Leute ins Stolpern. Erstens: Standardwerte müssen am Ende stehen - sobald ein Parameter einen Standardwert hat, muss auch jeder Parameter danach einen haben. Du kannst nicht void f(int a = 1, int b) schreiben, weil es keine Möglichkeit gäbe, b anzugeben und dabei a zu überspringen. Zweitens: Wenn eine Funktion in einem Header deklariert und anderswo definiert wird, setze den Standardwert nur in die Deklaration, wiederhole ihn niemals in der Definition - eine Wiederholung ist ein Compilerfehler.

Arrays und Vektoren übergeben

Ein rohes Array zerfällt bei der Übergabe zu einem Zeiger, sodass die Funktion seine Größe aus den Augen verliert - du übergibst fast immer die Länge daneben:

Da das Array zu einem Zeiger wurde, würde sizeof(arr) innerhalb von sum die Größe eines Zeigers liefern, nicht des Arrays - ein berüchtigter Fehler. Bevorzuge in modernem C++ einen std::vector (oder ein std::span in C++20), per const-Referenz übergeben, der seine eigene Größe mit sich trägt:

Beachte das const&: Lässt du es weg, kopiert jeder Aufruf den gesamten Vektor. Für einen Vektor mit vier Elementen ist das harmlos, aber für eine Million Elemente ist es ein stilles Performance-Loch.

Zeigerparameter

Du kannst auch einen Zeiger (T*) übergeben. Wie eine Referenz erlaubt das der Funktion, auf die Daten des Aufrufers zuzugreifen, aber ein Zeiger kann neu zugewiesen werden oder null sein - er ist also das richtige Werkzeug, wenn „kein Wert" eine legitime Option ist:

Der Aufrufer übergibt &value, um dessen Adresse zu teilen, und die Funktion schreibt über *out. Der entscheidende Unterschied zu Referenzen: Ein Zeiger könnte nullptr sein, daher sollte eine Funktion, die einen entgegennimmt, vor dem Dereferenzieren prüfen - diese Absicherung zu überspringen und einen Nullzeiger zu dereferenzieren ist undefiniertes Verhalten, meist ein Absturz. Wenn „kein Wert" nie Sinn ergibt, ist eine Referenz sauberer, weil sie von vornherein nicht null sein kann.

Weiter: Referenzen

Parameter sind der Ort, an dem Referenzen sich bezahlt machen, aber Referenzen sind ein eigenständiges Feature - Aliase, die du für jede Variable erstellen kannst, nicht nur innerhalb einer Funktionssignatur. Die nächste Seite geht tiefer darauf ein, wie Referenzen für sich allein funktionieren: wie man sie deklariert, warum sie sofort initialisiert werden müssen, der Unterschied zwischen einer lvalue-Referenz und einer const-Referenz und die subtilen Wege, auf denen eine Referenz baumelnd (dangling) werden kann.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Übergabe per Wert und Übergabe per Referenz in C++?

Die Übergabe per Wert kopiert das Argument in den Parameter, sodass Änderungen innerhalb der Funktion den Aufrufer nicht betreffen. Die Übergabe per Referenz (int&) macht den Parameter zu einem Alias für die Variable des Aufrufers, sodass Änderungen von außen sichtbar sind. Verwende void f(int x) zum Kopieren und void f(int& x), um das Original zu ändern.

Wann sollte man in C++ einen const-Referenzparameter verwenden?

Verwende const T&, wenn du ein großes Objekt lesen möchtest, ohne es zu kopieren und ohne der Funktion zu erlauben, es zu ändern - zum Beispiel void print(const string& s). Du erhältst die Geschwindigkeit der Übergabe per Referenz mit der Sicherheit der Übergabe per Wert. Für kleine Typen wie int oder char ist die einfache Übergabe per Wert genauso schnell.

Was sind Standardargumente in C++?

Standardargumente lassen einen Parameter einen Ersatzwert annehmen, wenn der Aufrufer ihn weglässt, z. B. void greet(string name = "there"). Standardwerte müssen die hinteren (am weitesten rechts stehenden) Parameter sein, und du gibst sie nur in der Deklaration an, nicht in der Definition, falls beide getrennt sind.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S