MDMit dem Zeh (plus plus) auf dem Schlauch StehenderGast#1731501
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:
1
Im Konstruktor: array[] = 1 2 4 8 16
2
3
Methode out():
4
i=0, array[0]=1
5
i=1, array[1]=2
6
i=2, array[2]=4
7
i=3, array[3]=8
8
i=4, array[4]=16
9
10
Destruktor aufgerufen
11
12
Methode out():
13
i=0, array[0]=0
14
i=1, array[1]=2
15
i=2, array[2]=4
16
i=3, array[3]=8
17
i=4, array[4]=16
18
19
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?
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
1
classIntVector{
2
private:
3
int*array;
4
unsignedintlen;
5
public:
6
IntVector(unsignedintlength);
7
IntVector();
8
~IntVector();
9
unsignedintsize();
10
int&at(unsignedinti);
11
voidout();
12
voidsetElement(unsignedinti,intvalue);
13
14
friendclassIterator;
15
16
private:
17
IntVector(constIntVector&rhs);// absichtlich nicht implementiert
18
IntVector&operator=(constIntVector&rhs);// absichtlich nicht implementiert
19
};
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.
MDMit dem Zeh (plus plus) auf dem Schlauch StehenderGast#1738878
Hallo nochmal,
einen Zuweisungsoperator kriege ich anscheinend hin, aber beim
Copy-Konstruktor habe ich ein Problem:
1
IntVector&IntVector::operator=(IntVector&ivec)
2
{
3
if(this!=&ivec)
4
{
5
delete[]array;
6
array=newint[ivec.size()];
7
for(unsignedinti=0;i<ivec.size();i++)
8
*(array+i)=ivec.at(i);
9
len=ivec.size();
10
}
11
return*this;
12
}
13
14
IntVector::IntVector(constIntVector&rhs)
15
{
16
array=newint[rhs.size()];
17
for(unsignedinti=0;i<rhs.size();i++)
18
*(array+i)=rhs.at(i);
19
len=rhs.size();
20
}
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!
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
1
classIntVector{
2
3
...
4
unsignedintsize()const;
5
...
6
};
und natürlich auch in der Implementierung das const noch anfügen
1
unsignedintIntVector::size()const
2
{
3
returnlen;
4
}
PS:
Auch im Op= ist das Argument eine const Referenz.
MDMit dem Zeh (plus plus) auf dem Schlauch StehenderGast#1738893
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? :)
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.
Eine eigene Frage?
Dieser Thread ist über 16 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.