Frage zu Referenzen



  • Ich habe zwar verstanden, das Referenzen nur andere Namen für die selbe Variable ist. Aber wozu ist das gut?

    Warum schreibt man

    void incrementByRef(int &i) { 
      ++i; 
    }
    

    und nicht

    void incrementByRef(int i) { 
      ++i; 
    }
    

    Wo ist der Vorteil der 1. Variante?



  • Der Vorteil der 1. Variante ist, das sie tut was sie soll. Die zweite Variante ist nutzlos, denn sie inkrementiert die lokale Kopie des übergebenen Parameters und beendet sich dann. Diese Funktion könntest Du genausogut leer lassen.



  • Vllt. sollte man noch erwähnen, dass (Gesetz dem Fall, man setzt Referenzen richtig ein ( 😃 )) man damit effizienter programmieren kann, da bei einem 'Call by Value' (sprich: Übergabe eines Wertes vie Kopie) und einem großen Objekt (z.B.: Klassen/Strukturobjekt) viel 'größere Datenmengen' kopiert werden müssen.

    Bei einer Referenz arbeitest du also mit dem referenzierten Objekt selbst.



  • Der Vorteil ist, dass Referenzen - wie du bereits sagtest - nur ein Alias für eine Variable sind. Angenommen, du hast eine Klasse, die double-Elemente o.ä. enthält. Wenn dein double 8 Byte groß ist, machen allein die double-Elemente 160 Bytes pro Objekt aus. Wenn du dann eine Instanz dieser Klasse als Argument/Wert (call-by-value) an eine Funktion übergibst, wird das Objekt kopiert - lokal für die Funktion. Damit bist du schon bei 320 Bytes (160 für das Original, 160 für die lokale Kopie des Funktionsaufrufs) insgesamt, wovon die Hälfte ohnehin unnötig ist. Wenn die Instanz aber als Referenz (call-by-reference) übergeben wird, wird nur ein Alias erzeugt und das Objekt muss nicht kopiert werden.

    Abgesehen von Speicher- und Laufzeiteinsparungen kommt der wichtigste Aspekt, weshalb man an dieser Stelle Referenzen (oder Zeiger, auch wenn diese keinen identischen Code beim Aufruf hervorbringen werden) verwendet, zusätzlich zum Tragen: Nur bei call-by-reference beziehen sich die Änderungen, die du innerhalb der Funktion vornimmst, auf das Original. Du kannst mit der Kopie des call-by-value-Aufrufs soviel mit dem Objekt anstellen, wie du willst, aber sobald die Funktion verlassen wird, findest du das alte Objekt mit den alten Werten vor, denn die Änderungen an der Kopie sind inzwischen verloren gegangen (Kopie wurde mit Verlassen der Funktion abgebaut). So sind Referenzen/Zeiger die einzigste Möglichkeit, aus Funktionen heraus übergebene Objekte zu ändern.

    [edit1]
    LordJaxom und CodeFinder waren schneller.
    [/edit1]

    [edit2]
    Zur Veranschaulichung von dem, was LordJaxom und ich gesagt haben:

    #include <iostream>
    
    void incrementByRef(int &i) 
    {
      ++i;
    }
    void incrementByVal(int i) {
      ++i;
    }
    
    int main()
    {
        int myVar = 42;
    
        incrementByVal(myVar);
        std::cout << "Wert von myVar: " << myVar << std::endl;
        incrementByRef(myVar);
        std::cout << "Wert von myVar: " << myVar << std::endl;
    
        std::cin.get();
    
        return 0;
    }
    

    [/edit2]



  • Vielleicht hilft dir das hier beim Verständnis:

    #include <iostream>
    using std::cout;
    using std::endl;
    
    //globale Variablen
    int a = 1; 
    int b = 2;
    
    void ausgabe()
    {
        cout << &a << ": " << a << "\t " << &b << ": " << b  << endl << endl;
    }
    
    void erfolgloser_swap( int x, int y ) // call-by-value
    {
      cout << "Kopien auf dem Stack: " << endl;
      cout << &x << ": " << x << "\t " << &y << ": " << y << endl;
    
      int temp = x;
      x = y;
      y = temp;
    
      cout << &x << ": " << x << "\t " << &y << ": " << y << endl;
      cout << "swap nur lokal erfolgreich." << endl;
    }
    
    void zeiger_swap( int * x, int * y ) // C-Lösung  call-by-reference
    {
      int temp = *x; // Inhalts-Operator // Dereferenzierungs-Operator
      *x = *y;
      *y = temp;
    }
    
    void referenzen_swap( int & x, int & y ) // C++-Lösung   call-by-reference
    {
      int temp = x;
      x = y;
      y = temp;
    }
    
    int main()
    { 
        cout << "Ausgangssituation: " << endl;
        ausgabe();
    
        cout << "Tausch mittels std::swap(x,y): " << endl;            
        std::swap(a,b); // Methode der Wahl aus der STL
        ausgabe();
    
        cout << "Tausch mittels Zeiger: " << endl;            
        zeiger_swap(&a, &b);
        ausgabe();
    
        cout << "Tausch mittels Referenzen: " << endl;            
        referenzen_swap(a,b);
        ausgabe();
    
        cout << "Erfolgloser Tausch, da nur lokale Kopien getauscht werden." << endl;            
        erfolgloser_swap(a,b);
        ausgabe();
    
        cout << "Tausch mittels Register eax und ebx: " << endl;         
        //swap (a,b) 
        __asm("mov _b, %eax"); //AT&T Syntax bei Dev-C++ 
        __asm("mov _a, %ebx"); 
        __asm("mov %eax, _a"); 
        __asm("mov %ebx, _b"); 
        ausgabe(); 
    }
    

Anmelden zum Antworten