Wann darf man etwas in C++ _nicht_ aus einer Funktion returnen?


  • Gesperrt

    Hallo noch mal,

    ich versuche weiterhin, meine Kenntnisse etwas aufzufrischen... Was sollte man nicht aus einer Funktion returnen?

    1. simpler int-Wert ✔
    2. neue struct ✔
    3. std::string ✔
    4. neues Array 🙅♂
    5. etwas durch malloc() reserviertes 🙅♂
    6. etwas mit new initialisiertes 🙅♂
    7. ...

    Was gibt es noch? Liegen Unterschiede zu C vor?



  • @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?


  • Gesperrt

    @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?

    1. simpler int-Wert ✔
    2. neue struct ✔
    3. 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.

    1. 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.

    1. etwas durch malloc() reserviertes 🙅♂
    2. etwas mit new initialisiertes 🙅♂
    3. ...

    Bei malloc und new 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 wie allocator.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ählen 😉

    Was 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;
       }
    };
    

Anmelden zum Antworten