crash bei Kopierkonstruktior



  • müsste eine ganz einfache aufgabe sein, ich kriegs trotzdem nicht hin. einen kopierkonstuktor für eine klasse zu schreiben.

    Liste::Liste(const Liste& )
    {...}
    

    was der konstruktor macht müsste keine rolle spielen, er wird nie aufgerufen und es macht keinen unterschied ob er leer ist.

    das ist der code in der main methode:

    Liste l1;
    	cout<<l1<<endl;
    

    den operator für die liste hab ich überladen:

    ostream& operator<<(ostream& os, Liste l)
    {
    		ListEl *el=l.first;	
    	if(el!=NULL)
    	{
    	do
    	{
    		os<<*el<<endl;	
    		os<<"------------------"<<endl;
    	}
    	while((el=el->getNext())!=NULL);
    	}
    	return os;
    }
    

    ohne den kopierkonstruktor wird alles richtig ausgegeben, aber mit dem ding crasht es einfach mit der fehlermeldung:

    Unbehandelte Ausnahme bei 0x775115de in Tutorial_01.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x4fdaffde.
    

    was zum teufel soll ich damit anfangen?



  • Bist du sicher, das er nie aufgerufen wird? Wenn ja, dann is dein Fehler woanders. Code, der nicht aufgerufen wird, kann keinen Fehler verursachen (zumindest, wenn er fehlerfrei kompiliert werden kann).



  • die lösung war dass ich den einzigen beiden variablen =NULL zuweise, keine ahnung wieso.

    hab jedenfalls noch ein problem mit dem destruktor: wieso zur hölle wird er immer direkt nach dem cout aufgerufen?
    zumindest wird die ausgabe des destruktors immer nach dem cout ausgegeben...es müsste überhaupt nicht ausgegeben werden weil ich manuell keine objekte dieser klasse lösche.



  • Der Destruktor wird immer aufgerufen, wenn ein Objekt zerstört wird. Und meine Glaskugel sagt mir, dass nach dem cout ncihts mehr in deiner main-Funktion steht, also verlässt deine Liste den Scope und wird daher automatisch zerstört.



  • Da wird eine Kopie erzeugt:

    ostream& operator<<(ostream& os, Liste l)
    

    und später natürlich der Destruktor aufgerufen.



  • Nikolei schrieb:

    müsste eine ganz einfache aufgabe sein, ich kriegs trotzdem nicht hin. einen kopierkonstuktor für eine klasse zu schreiben.

    Liste::Liste(const Liste& )
    {...}
    

    was der konstruktor macht müsste keine rolle spielen, er wird nie aufgerufen ...

    Hallo Nikolei,

    Du kannst nur sicher sein, dass er 'nie' aufgerufen wird, wenn Du den Kopierkonstruktor und auch den gleich den Zuweisungsoperator private deklarierst. Also:

    class Liste {
    // ..
    private:
        Liste( const Liste& ); // stilllegen
        Liste& operator=( const Liste& ); // Bem.: in C++11 ginge auch delete
    };
    

    Wenn Du Liste doch aus Versehen kopierst, so meckert gleich der Compiler; etwa mit einer Fehlermeldung wie

    cannot access private member declared in class 'Liste'

    In Deinem Fall würde sich Dein Code gar nicht übersetzen lassen, wie manni66 bereits bemerkt hat, wird bei der Übergabe an die Streaming-Funktion der Kopierkonstruktor aufgerufen.

    Ändere den Aufruf nach

    ostream& operator<<(ostream& os, const Liste& l)
    

    .. und achte darauf, dass es für die Methode ListEl::getNext auch eine const-Variante gibt.

    Nikolei schrieb:

    den operator für die liste hab ich überladen:

    ostream& operator<<(ostream& os, Liste l)
    {
    		ListEl *el=l.first;	
    	if(el!=NULL)
    	{
    	do
    	{
    		os<<*el<<endl;	
    		os<<"------------------"<<endl;
    	}
    	while((el=el->getNext())!=NULL);
    	}
    	return os;
    }
    

    Besser:

    ostream& operator<<(ostream& os, const Liste& l)
    {
        for( const ListEl* el = l.first; el != 0/*nullptr*/; el = el->getNext() )
        {
            os<<*el<<endl;	
            os<<"------------------"<<endl;
        }
        return os;
    }
    

    Gruß
    Werner



  • Ich rate mal, dass Du, Nikolei, die Dreierregel verletzt hast.

    Wenn du keinen Kopierkonstruktor und keinen Zuweisungsoperator brauchst, ist es ganz einfach, diese zu "deaktivieren". Wenn dann dein Programm noch fertig kompiliert und erfolgreich gelinkt wird, wird wirklich nirgends versucht, den Kopierkonstruktor zu verwenden. Probiere folgendes:

    class Liste
    {
      :::
    
    private:
      Liste(Liste const&);
      Liste& operator=(Liste const&);
    
      :::
    }
    

    Nur diese Dinger private deklarieren, sie aber undefinieren lassen.

    Edit: Da war ich wohl 3 Minuten zu spät. 😉

    Edit2: Bei einem Compiler, der die C++2011-Regeln richtig befolgt, ist das nicht mehr notwendig. Du hast ja einen eigenen Destruktor (nehme ich mal an) und in dem Falle würde der Compiler Kopierkonstruktor und Zuweisungsoperator nicht mehr selbst definieren.


  • Mod

    krümelkacker schrieb:

    Edit2: Bei einem Compiler, der die C++2011-Regeln richtig befolgt, ist das nicht mehr notwendig. Du hast ja einen eigenen Destruktor (nehme ich mal an) und in dem Falle würde der Compiler Kopierkonstruktor und Zuweisungsoperator nicht mehr selbst definieren.

    bist du sicher?



  • camper schrieb:

    bist du sicher?

    Das ist zumindest "der neue Ansatz": Deklariert der Nutzer irgtendwas von copy/move ctor/assigment oder dtor, dann bedeutet das, dass die Kopier-Semantik eine "besondere" ist die der Compiler nicht kennen kann. Dementsprechend möchte man nicht, dass er irgendwelche dieser special member functions selbst generiert.

    Aus C++98 Kompatibilitätsgründen gibt es jedoch noch eine Ausnahmeregelung, die aber in C++2011 schon den Status deprecated hat. An diese Ausnahmregel dachte ich vorhin nicht mehr. Das heißt, ich würde erwarten, dass ein C++2011 Compiler das Programm

    struct a {
      a() {}
      ~a() {cout<<"x";}
    };
    
    int main() {
      a x;
      a y = x;
    }
    

    "frisst" aber hoffentlich eine Warnung ausgibt à la "implicit generation of copy/move operations in this case is deprecated. If you really need a compiler generated copy/move operation, be explicit and use the =default syntax." oder so etwas ähnliches. 😉

    So eine Warnung wird Neulingen sicherlich zu Gute kommen. Dann wissen sie entweder, dass sie einen Fehler gemacht haben oder dass sie das Programm so umbauen müssen:

    struct a {
      a() {}
      ~a() {cout<<"x";}
      a(a const&) = default;
      a& operator=(a const&) = default;
    };
    
    int main() {
      a x;
      a y = x;
    }
    

    damit die Warnung weggeht und der Code auch in Zukunft (C++1Y?) laufen wird.


Anmelden zum Antworten