Wann darf man etwas in C++ _nicht_ aus einer Funktion returnen?
-
Hallo noch mal,
ich versuche weiterhin, meine Kenntnisse etwas aufzufrischen... Was sollte man nicht aus einer Funktion returnen?
- simpler int-Wert
- neue struct
- std::string
- neues Array
- etwas durch malloc() reserviertes
- etwas mit
new
initialisiertes - ...
Was gibt es noch? Liegen Unterschiede zu C vor?
- simpler int-Wert
-
@EinNutzer0 sagte in Wann darf man etwas in C++ _nicht_ aus einer Funktion returnen?:
neues Array
probier's doch
etwas durch malloc() reserviertes
Nein. Aber warum?`
etwas mit new initialisiertes
Warum willst
new
überhaupt verwenden?
-
@Swordfish sagte in Wann darf man etwas in C++ _nicht_ aus einer Funktion returnen?:
neues Array
probier's doch
Das wäre doch irgendwann "weg", also stale, das möchte man doch vermeiden.
Ich hab nach Dos and Don'ts gesucht, wenn man so möchte, also quasi nach einem Standardidiom in C und C++...
Danke für jede Hilfe.
-
@EinNutzer0 sagte in Wann darf man etwas in C++ _nicht_ aus einer Funktion returnen?:
Hallo noch mal,
ich versuche weiterhin, meine Kenntnisse etwas aufzufrischen... Was sollte man nicht aus einer Funktion returnen?
- simpler int-Wert
- neue struct
- std::string
Das kann man zusammenfassen als "by value" zurückgeben und ist generell kein Problem, wenn die Klasse korrekt implementiert wurde. Das beinhaltet dann auch
std::vector
,std::array
und alle anderen Objekte.- neues Array
Ein C-Array ist ein Sonderfall, da es in vielen Fällen in einen
T*
zerfällt und man nur einen Zeiger auf das erste Element zurückgibt, anstatt das ganze Array zu kopieren:auto f() { int a[] = {1, 2, 3}; return a; }
Hier findet in Zeile 4 eine "array-to-pointer"-Konvertierung statt, wodurch der Code äquivalent zu diesem hier ist:
auto f() { int a[] = {1, 2, 3}; return &a[0]; }
Du würdest also einen Zeiger auf ein funktions-lokales Objekt auf dem Stack zurückgeben. Der Stack-Frame einer Funktion wird wieder freigegeben, wenn die Funktion zurückkehrt und dieser Stack-Speicher kann dann danach für etwas anderes verwendet werden, wie lokale Variablen in einer anderen Funktion oder sogar Rücksprungadressen. Auch wurden hier die Destruktoren der Array-Objekte aufgerufen, es handelt sich also um ungültige Objekte und der Zugriff auf diese ist UB.
Wenn du stattdessen
std::array
verwendest, gibt es hierbei allerdings kein Problem. Diese Klasse hat einen Kopier-Konstruktor bei dem das gesamte Array kopiert wird, wenn man es "by value" zurückgibt.- etwas durch malloc() reserviertes
- etwas mit
new
initialisiertes - ...
Bei
malloc
undnew
würde ich sogar noch weiter gehen und sagen, dass man die in modernem C++ überhaupt nicht verwenden sollte. Selbst wenn man z.B. eigene Container-Klassen implementiert, wo man meinen könnte dass man die braucht, sollte man lieber Dinge wieallocator.allocate()
verwenden. Einzige Ausnahme ist vielleicht, wenn man einen Standard-Allocator implementiert, aber die Entwickler, die so etwas machen müssen, kann man an einer Hand abzählenWas gibt es noch? Liegen Unterschiede zu C vor?
In C++ gibt es auch noch Referenzen. Genau wie mit Pointern kann man auch "Dangling References" erzeugen, wenn man nicht aufpasst:
std::string& f() { std::string a = "abc"; return a; }
Genau wie wenn ich einen Pointer auf den String zurückgebe, verweist die hier zurückgegebene Referenz auf ein ungültiges Objekt, da der String zerstört wird, sobald die Funktion zurückkehrt.
Das bezieht sich natürlich nur auf Objekte, die tatsächlich ungültig werden. So etwas hier ist im Allgemeinen unproblematisch und sogar erwünscht, da es eine Kopie spart:
struct A { std::string a = "abc"; const std::string& f() { return a; } };
- simpler int-Wert