Wieso geht das nur so?
Ist ne eigene Klasse!!!!!!!!!!!!!
String aaa = *this; //das geht
cout << aaa.pg; //das geht
cout <<*this.pg; //geht nichtttttttttttttttttttttttttttt
cout << this->pg; //das geht
wieso nur?
wieso geht das nicht *this.pg;
das bedeutet dann ja eigentlich
das aus der Funktion operator=(const String &sdd)
das hier gemacht wird operator=(String *this; const String &sdd)
kann man sich das so ungefär vorstellen
Franziskaner schrieb:
> das bedeutet dann ja eigentlich>>> das aus der Funktion operator=(const String &sdd)>> das hier gemacht wird operator=(String *this; const String &sdd)>> kann man sich das so ungefär vorstellen
Ja, so in etwa.
Eine Memberfunktion einer Klasse ist intern eine ganz normale Funktion,
der ein Zeiger auf das Objekt für welches es aufgerufen wird, mitgegeben
wird.
aus
1
classA
2
{
3
public:
4
voidfoo(intj)
5
{i=j;}
6
7
protected:
8
inti;
9
};
10
11
intmain()
12
{
13
Aa;
14
15
a.foo(5);
16
}
macht der Compiler konzeptionell für sich
1
structA
2
{
3
inti;
4
};
5
6
voidA_foo(structA*this,intj)
7
{
8
this->i=j;
9
}
10
11
intmain()
12
{
13
structa;
14
15
A_foo(&a,5);
16
}
Ein Operator ist im Grunde auch nur eine normale Memberfunktion.
Lediglich der Aufruf sieht im Code anders aus.
In der Tat haben die ersten C++ Compiler genau so gearbeitet: Die haben
den C++ Code nach so einem Schema in C übersetzt und dann den ganz
normalen C Compiler benutzt. In der Zwischenzeit hat sich aber C++ von C
in einigen Bereichen schon zu weit entfernt, so dass das heute nicht
mehr gehen würde.
hab nämlich das Problem das 2 Objekte miteinander verglichen werden
müssen
und da wird dann ne referenz mit nem zeiger verglichen so wie ich das
sehe
if (this == &a)
bla bla
return *this oder a;
bei a wird da ne referenz übergeben und bei this dann der Zeiger
Franziskaner schrieb:
> hab nämlich das Problem das 2 Objekte miteinander verglichen werden> müssen> und da wird dann ne referenz mit nem zeiger verglichen so wie ich das> sehe>>> if (this == &a)>> bla bla>>> return *this oder a;>>> bei a wird da ne referenz übergeben und bei this dann der Zeiger
Basics!
this ist ein Zeiger, das ist korrekt.
Aber &a kann keine Referenz sein. Referenzen tauchen immer nur bei
Deklarationen auf. Ansonsten merkst du nie irgendetwas von einer
Referenz!
& ist hier der Adress-Of Operator! Er liefert die Speicheradresse von a
doch kann
operator = (const Daten &a)
if (this == &a) denke mal das da die Adressen verglichen werden
alternativ gehen auch die Werte
this->daten == a.daten
alsi die neuen Daten sollen in die alten Daten geschrieben werden wenn
ungleich
hab ich schon getestet
Franziskaner schrieb:
> doch kann
nein, kann nicht
>> operator = (const Daten &a)
Das ist eine Referenz ...
>> if (this == &a) denke mal das da die Adressen verglichen werden
... und hier hat das Zeichen & die Bedeutung des AdressOf Operators.
Das Zeichen & hat unterschiedliche Bedeutungen, je nachdem wo es
verwendet wird.
>> alternativ gehen auch die Werte
Auch das ist falsch.
> alsi die neuen Daten sollen in die alten Daten geschrieben werden wenn> ungleich
Spar dir den Vergleich und machs richtig. Wenn in einem op= gleich am
Anfang der Vergleich vorkommt
1
T&T::operator=(constT&rhs)
2
{
3
if(&rhs!=this){
4
...
5
}
6
7
return*this;
8
}
dann hat dieser Operator ein Problem. In einem korrekt geschriebenem op=
benötigt man diesen Vergleich nicht.
>> hab ich schon getestet
Was du getestet hast, weiß ich nicht. Aber dein C++ Verständnis ist
lausig.
Franziskaner schrieb:
> Das ist das Beispiel einen Professors das ist sein Skript> ich glaub nicht das er misst schreibt
Oh. Das sind die schlimmsten.
Sag ihm einen schönen Gruss von mir und er soll mal einen C++ Kurs
belegen.
Franziskaner schrieb:
> Da soll der Zuweisungskon. getestet werden> und bei daten1 = daten1 soll er nichts machen>> nur bei daten1 = daten2 soll er kopieren
Aha.
Mal nur so nebenbei. Was denkst du. Wie oft kommt wohl in einem
durschschnittlichen Programm die erste Zeile vor? Von 10Millionenn
aufrufen sind maximal 2 oder 3 dabei, bei denen das tatsächlich
passiert. Das bedeutet aber im Umkehrschluss, du machst 9 Millionen 900
Tausend und ein paar Zerquetsche Vergleiche völlig umsonst (denn du
musst ja dann sowieso zuweisen) nur damit du bei den 2 oder 3
Zuweisungen, bei denen du dir die Zuweisung hättest sparen können etwas
Zeit einsparst.
Wow: Super Optimierung!
Auch Vergleiche kosten Zeit!
Franziskaner schrieb:
> Aber du vergleichst doch da>>> die adressen oder was sonst>> if( &rhs != this )
Ganz genau.
Und wenn du sowas in einem op= siehst, weißt du sofort, dass das ein C++
Anfänger geschrieben hat, der von Exception-Safe programmieren keine
Ahnung hat. Ein op=, der exception safe ist, benötigt diese Abfrage
nicht. Und als Optimierung taugt es ebensowenig, weil das bischen
Zeiteinsparung bei der Zuweisung locker durch die zusätzliche Abfragen
bei den Zuweisungen bei denen tatsächlich zugewiesen werden muss,
aufgefressen wird.
wenn ich dir jetzt noch schreib das wir die Kopie mit strcpy (war wo
anders strlen)
gemacht haben (natürlich nur wenns Unterschiedlich ist) und der Combiler
davor schon von sich aus warnt dann wirste warscheinlich...
Alles klar. ihr macht dynamisches Resourcenmanagement
Gegen strcpy an sich ist nichts einzuwenden. Aber in einem op= muss man
das ganze richtig machen.
Die falsche (vermeintlich richtige) Version ist
1
String&String::operator=(constString&rhs)
2
{
3
if(&rhs!=this){
4
delete[]pointer;
5
pointer=newchar[strlen(rhs.pointer)+1];
6
strcpy(pointer,rhs.pointer);
7
}
8
9
return*this;
10
}
die korrekte Version ist
1
String&String::operator=(constString&rhs)
2
{
3
char*tmp=newchar[strlen(rhs.pointer)+1];
4
strcpy(tmp,rhs.pointer);
5
delete[]pointer;
6
pointer=tmp:
7
8
return*this;
9
}
Der Unterschied:
denk mal darüber nach, was wohl in Version 1 mit dem Objekt passiert,
wenn new eine Exception wirft und keinen Speicher allokieren kann. Zu
dem Zeitpunkt ist der delete [] pointer schon durch und das String
Objekt steht ohne gültige Speicherfläche da.
In Version 2 kann das nicht passieren. Der delete geschieht erst nachdem
der neue Speicher allokiert wurde.
Karl heinz Buchegger schrieb:
> Spar dir den Vergleich und machs richtig. Wenn in einem op= gleich am> Anfang der Vergleich vorkommt ... dann hat dieser Operator ein Problem. > In
einem korrekt geschriebenem op= benötigt man diesen Vergleich nicht.
Würde ich in dieser apodiktischen Form nicht unterschreiben.
Ich kann mir durchaus Fälle vorstellen, in denen man damit besser fährt
oder garnicht darum herum kommt. Beispielsweise weil man inkonsistente
oder Information verlierende Zwischenzustände kriegen kann, insbesondere
wenn private base classes dabei sind. Oder wenn man um das bei Identität
zu vermeiden um's Eck herum über temporaries arbeiten muss, und dann
dreht sich deine Statistik ins Gegenteil um, weil man das in 99% der
Fälle eigentlich nicht braucht.
Bei uns im Skript steht das !!!!!!!!!!!!!!
if( &rhs != this ) {
delete [] pointer;
pointer = new char [ strlen( rhs ) + 1 ];
strcpy( pointer, rhs.pointer );
}
return *this;
}
genau so lol
aber deine Version ist besser das ist klar
wir haben halt die String klasse nachprogrammiert
und die meisten dachten so wie ich das man die abfrage machen muss
steht ja auch im sktript
A. K. schrieb:
> dreht sich deine Statistik ins Gegenteil um, weil man das in 99% der> Fälle eigentlich nicht braucht.
Den Vergleich benötigt man im wesentlichen eigentlich nur wenn
dynamische Allokierungen im Spiel sind. In den anderen Fällen mag es
Fälle geben, in denen tatsächlich ein Speedup möglich ist und die
Kopieraktion im Vergleich zur Abfrage unendlich teuerer ist. Zb. wenn
komplette Datenbanken kopiert werden.
Bei dynamischen Resourcen ist die Reihenfolge immer:
* zuerst die neuen Resourcen allokieren
* dann umkopieren
* dann die vorhandenen Klassendaten zerstören
* die neu allokierten Pointer an die Membervariablen zuweisen.
Hält man sich nicht an diese Reihenfolge, kommt man unweigerlich in
Probleme, sobald ein new (und der ist das eigentliche Problemkind) eine
Exception wirft. Der delete der bisherigen Resource muss solange als
möglich hinausgezögert werden. Sobald die delete durchlaufen, darf es
keine Möglichkeit für eine Exception mehr geben. (Gegebenenfalls muss
man sie im op= mit einem catch Block abfangen und am Ende einen rethrow
machen. Aber oberstes Ziel muss es immer sein, die Klasse in einem
konsistenten Zustand zu halten)
Basisklassen sind kein Problem. Deren Aufruf des op= kommt ganz an den
Anfang des op=, sodass die restliche Zuweisungssequenz nur dann
durchlaufen wird, wenn auch die Basisklasse korrekt zugewiesen werden
konnte. Wirft die Basisklasse eine Exception, darf auch der eigene op=
nicht gemacht werden.
Franziskaner schrieb:
> die Frage ist wie macht es die Klasse String> letztändlich möchte idiese Klasse für zukünftige Programme verwenden
Solange du nicht weißt, was Exceptions sind, kannst du es auf beide
Arten machen. Sobald ihr aber Exceptions durch habt, sollte eure Form
für dich tabu werden - sie ist nicht Exception-safe.
Ich weis was Exceptions sind ich lerne für die künftige c++ Prüfung
so komplette Projekte haben wir nicht gemacht es dreht sich halt nunmal
um "Basics" immerhin haben wir nen kopletten container per hand
nachprogrammiert aber da war soviel c drinnen mit pop und front usw
das die meisten jetzt bei c++ hängen und komplexe c++ Problem gar nicht
erkennen weil man vor lauter c nicht c++ sieht
Franziskaner schrieb:
> Ich weis was Exceptions
Gut.
Dann musst du dir immer vor Augen halten, dass ein new eine Exception
werfen kann.
Wenn hier
1
if(&rhs!=this){
2
delete[]pointer;
3
pointer=newchar[strlen(rhs)+1];
eine Exception auftritt, dann hat dein String Objekt seine bisherigen
Daten schon über Bord geworfen. Und damit zeigt pointer auf Speicher,
der nicht mehr dem Objekt gehört. Der op= wird aufgrund der Exception
verlassen und der nächste Aufruf einer Memberfunktion von String, die
pointer benutzt, macht dann BUMM!
Ich weiß, man sieht diese Form häufig. Das macht sie aber nicht
richtiger.
soweit haben wir das nicht getrieben
wir haben eine
try....
und einen catch
block in der main definiert
bei catch int //gib das aus
bei catch double //gib was anderes aus
und wenn zb mal eine Medtode einer Klasse nen bestimmten
Zählerstand hatte dann wurde mit throw irgendwas ausgelöste
das ist jetzt nicht so komplizeirt
Franziskaner schrieb:
>> bei catch int //gib das aus> bei catch double //gib was anderes aus>> und wenn zb mal eine Medtode einer Klasse nen bestimmten> Zählerstand hatte dann wurde mit throw irgendwas ausgelöste
Ich hoffe mal, dieser Zählerstand war stellvertretend für einen
Fehlerfall.
Exceptions sind eigentich dafür gedacht, Fehler an den Aufrufer zu
übermitteln. Wobei die reine Lehre da auch noch unterscheidet zwischen
Fehlern, mit denen ein Aufrufer rechnen muss und Fehlern mit denen er
nicht rechnen muss.
Wird eine Datenbank nach einem bestimmten Eintrag durchsucht, dann muss
der Aufrufer damit rechnen, dass der Eintrag nicht gefunden wird. In so
einem Fall ist eine Exception nicht angebracht und das Nichtfinden wird
über ganz normle Kanäle (zb durch einen NULL Pointer als Return Wert)
angezeigt.
Greift man aber auf eine Datei zu, dann muss der Aufrufer nicht damit
rechnen, dass just in diesem Moment jemand die CD aus dem Laufwerk
rausfährt.
Allerdings sind die Übergänge hier fliessend.
Und ja: es gibt auch die andere Schule, die auch normale Ergebnisse
anstelle von Return Werten über Exceptions zurückgibt.
Meine persönliche Meinung, die ich aber niemandem aufdränge: Im letzten
Fall werden Exceptions zu etwas vergewaltigt, wofür sie nie gedacht
waren. Aber das ist IMHO.
bei uns gabs ne aufgabe biergarten und wenn der voll war wurde auch eine
Exceptions ausgelöst cout << " Biergarten voll" füe falscheingaben zb in
statt double
wurde auch eine Exceptions ausgelöst
Franziskaner schrieb:
> bei uns gabs ne aufgabe biergarten und wenn der voll war wurde auch eine> Exceptions ausgelöst cout << " Biergarten voll"
Ist Grenzwertig.
Meine Ansicht: Würd ich nicht machen.
Wenn ich in einen limitierten Container was einfüge, und im Container
ist kein Platz, dann ist das ein Ereignis mit dem ich als Aufrufer
rechnen muss. Ist aber tatsächlich Ansichtssache, ob ich als Aufrufer da
einen Returncode (true, false) angenehmer finde, oder doch eine
Exception bevorzuge.
> füe falscheingaben zb in> statt double> wurde auch eine Exceptions ausgelöst
Das finde ich soweit ok, auch wenn ein Programmteil immer mit einer
Fehleingabe rechnen muss.
meine hauptprobleme waren zeiger und referenzen mit diesem this denke
ich mal
hab ich das abgeschlossen
das ist im übrigen das größte Problem bei uns Studenten gewesen
Vererbung
Inteface
friend
stream klassen
find ich jetz
auf unsere "kleinen" Projekten bezogen nicht so schwer
morgen mach jetzt nochmal über die Templatets
und über die Containerklassen her
das sollte man am besten auswendig wissen wie man da sucht und einfügt
und bei doppelten einträgen nicht macht usw
Biergarten voll ist ein grundlegender Fehler, keine Frage.
Damit muß und kann man nicht rechnen, ein Ausnahmezustand ohne
jeden Zweifel.
Im Übrigen hat KHB vollkommen recht damit, daß das delete nicht
stattfinden darf, solange der Rest noch schief gehen kann.
Ob man trotzdem vorher einen Test macht, ob an sich selbst zugewiesen
werden soll, ist aber davon unabhängig. Ich würde es in der Regel
nicht machen (eine solche Kopie ist unsinnig, und wenn sie unnötig
lange dauert, ist der Aufrufer selber schuld - zu blöd halt).
Wenn sein Prof es so machen will, warum nicht? Tut ja nicht weh,
zumindest nicht übermäßig.
Klaus Wachtler schrieb:
> Ob man trotzdem vorher einen Test macht, ob an sich selbst zugewiesen> werden soll, ist aber davon unabhängig.
Right
> Ich würde es in der Regel> nicht machen (eine solche Kopie ist unsinnig, und wenn sie unnötig> lange dauert, ist der Aufrufer selber schuld - zu blöd halt).> Wenn sein Prof es so machen will, warum nicht? Tut ja nicht weh,> zumindest nicht übermäßig.
Das Problem, das ich sehe ist, das dieser Vergleich als unbedingt
notwendig gelehrt wird. Ich selbst habs auch so gelernt, bis ich dann in
diversen Newsgroups von echten Profis (Herb Suttner, Jusuttis, Francis
Glasborrow, etc) gelernt habe, wo der Schuh bei dieser Lösung drückt.
Schade, dass Herb seine regelmässige "Guru of the week" Kolumne in
comp.lang.c++.moderated schon lange aufgegeben hat. Man konnte so
unendlich viel von ihm lernen.