www.mikrocontroller.net

Forum: PC-Programmierung C++ Problem mit Iterator / Destruktor


Autor: Mit dem Zeh (plus plus) auf dem Schlauch Stehender (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
ich hab grad ein Knoten im Kopf weil ich ein selbst geschriebenes C++ 
Programm nicht versteh ;)

Der Code ist im Anhang. Die Ausgabe ist bei mir wie folgt:

Im Konstruktor: array[] = 1 2 4 8 16

Methode out():
i=0, array[0]=1
i=1, array[1]=2
i=2, array[2]=4
i=3, array[3]=8
i=4, array[4]=16

Destruktor aufgerufen

Methode out():
i=0, array[0]=0
i=1, array[1]=2
i=2, array[2]=4
i=3, array[3]=8
i=4, array[4]=16

Destruktor aufgerufen

Jetzt meine Fragen,
1.) Wieso wird der Destruktor zwei mal aufgerufen? Ich lege ja nur ein 
Objekt der Klasse IntVector an?
2.) Was passiert mit dem ersten Element von array[] zwischen den beiden 
Aufrufen von vector.out() so dass der Wert einmal 1 ist und einmal 0?

: Verschoben durch User
Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hier wird ein neues Object angelegt

> Iterator it(vector);
vector wird kopiert!

du müsste es mit
class Iterator {
private:
  IntVector* intVector;
  unsigned int index;

public:
  Iterator(IntVector&); <<<<<& wichtig!
  Iterator(IntVector*);
  int* next();
};

Autor: Mit dem Zeh (plus plus) auf dem Schlauch Stehender (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah danke... kaum macht mans richtig schon gehts :)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter hat das Problem ja schon identifiziert.

Deine Klasse IntVector ist eine gefährliche Klasse: Sie betreibt 
dynamisches Datenmanagement, hat aber keinen von dir geschriebenen 
Kopierkonstruktor. In dem Fall erzeugt sich der Compiler selbst einen, 
der leider das falsche tut: Er kopiert alle Member, auch den Pointer. 
Und damit hast du 2 Objekte, die auf dieselben new-allokierten Daten 
verweisen. Sobald das erste der beiden Objekte zerstört wird, sind auch 
die Daten futsch. Das übrig gebliebene Objekt greift auf Daten zu, die 
nicht mehr existieren bzw. versucht die dann auch zu deleten.

-> schwerer Fehler

Du hast 2 Möglichkeiten
* entweder einen Kopierkonstruktor und Zuweisungsoperator selber
  schreiben
* Oder die Klasse so absichern, dass von Objekten keine Kopien erzeugt
  werden können.

Letzteres geht so
class IntVector {
private:
  int* array;
  unsigned int len;
public:
  IntVector(unsigned int length);
  IntVector();
  ~IntVector();
  unsigned int size();
  int& at(unsigned int i);
  void out();
  void setElement(unsigned int i, int value);

  friend class Iterator;

private:
  IntVector( const IntVector& rhs );               // absichtlich nicht implementiert
  IntVector& operator=( const IntVector& rhs );    // absichtlich nicht implementiert
};

versuchst du jetzt (auch irrtümlich) von einem IntVector eine Kopie zu 
erzeugen, dann klopfen dir entweder Compiler oder Linker auf die Finger.

Sobald du in einer Klasse dynamisch mittels new allokierst, solltest du 
dir angewöhnen, zumindest als Minimallösung die Kopiersperre durch 
private definierte und nicht implementierte CCtor und op= einzurichten. 
Spart viel Kopfzerbrechen.

Autor: Mit dem Zeh (plus plus) auf dem Schlauch Stehender (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal,

einen Zuweisungsoperator kriege ich anscheinend hin, aber beim 
Copy-Konstruktor habe ich ein Problem:

IntVector& IntVector::operator=(IntVector& ivec)
{
  if(this != &ivec)
  {
    delete [] array;
    array = new int[ivec.size()];
    for(unsigned int i=0; i<ivec.size(); i++)
      *(array+i) = ivec.at(i);
    len = ivec.size();
  }
  return *this;
}

IntVector::IntVector(const IntVector& rhs)
{
  array = new int[rhs.size()];
  for(unsigned int i=0; i<rhs.size(); i++)
    *(array+i) = rhs.at(i);
  len = rhs.size();
}

Jetzt bekomme ich vom Compiler die Fehlermeldung:
error: passing `const IntVector' as `this' argument of `unsigned int 
IntVector::size()' discards qualifiers

Ohne das "const" kompiliert es zwar, aber wenn ich das weglasse, dann 
wäre es ja kein Copy-Konstruktor mehr? Zu Hülf!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit dem Zeh (plus plus) auf dem Schlauch Stehender schrieb im Beitrag 
#1738878:

> Jetzt bekomme ich vom Compiler die Fehlermeldung:
> error: passing `const IntVector' as `this' argument of `unsigned int
> IntVector::size()' discards qualifiers


Dein Compiler teilt dir mit, dass du die Memberfunktion size nicht 
aufrufen darfst.
In deinem Copy Contructor hast du mit dem const in der Argumentliste dem 
Aufrufer gegenüber die Zusicherung gemacht, dass du das Argument nicht 
verändern wirst.
Nur: die Memberfunktion size() macht diese Zusicherung nicht! D.h. aus 
Sicht des Aufrufers: er muss damit rechnen, dass sich das Objekt durch 
Aufruf der Funktion size() verändern wird.
Das passt jetzt aber nicht zusammen: Auf der einen Seite macht der Copy 
Constructor die Zusicherung: Ich ändere das Objekt nicht, auf der 
anderen Seite möchte er eine Funktion aufrufen die nicht garantiert, das 
das Objekt nicht verändert wird.

Lösung des Dilemmas:
Da size() das Objekt ja nicht verändern braucht, machen wir die Funktion 
einfach const. Dann sind alle glücklich
class IntVector {

...
  unsigned int size() const;
...
};

und natürlich auch in der Implementierung das const noch anfügen
unsigned int IntVector::size() const
{
  return len;
}


PS:
Auch im Op= ist das Argument eine const Referenz.
IntVector& IntVector::operator=(const IntVector& ivec)

Das man einen Op= so nicht schreibt, weil er nicht exception safe ist, 
lass ich erst mal unkommentiert. Das wird zuviel auf einmal.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ivec.size()

ist die methode als const declariert?

Autor: Mit dem Zeh (plus plus) auf dem Schlauch Stehender (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah, anscheinend muss ich alles und jeden "const" machen, also alle 
Elementfunktionen die ich im Copy-Konstruktor verwenden will... hmpf. 
Kann sich der Compiler das nicht denken? :)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit dem Zeh (plus plus) auf dem Schlauch Stehender schrieb im Beitrag 
#1738893:
> Ah, anscheinend muss ich alles und jeden "const" machen, also alle
> Elementfunktionen die ich im Copy-Konstruktor verwenden will... hmpf.

Nein.
Du sollst alle Memberfunktionen, die das Objekt nicht verändern, als 
const Funktionen machen! Unabhängig davon, ob sie im Copy Constructor 
verwendet werden oder nicht.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du könntest auch auf private sachen ohne Methode zugreifen, braucht also 
die Methode size nicht zwingend.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.