C++ und this

Gast #1306931
Lesenswert?

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;
#1306961
Lesenswert?

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
class A
2
{
3
  public:
4
    void foo( int j )
5
    { i = j; }
6

7
  protected:
8
    int i;
9
};
10

11
int main()
12
{
13
  A a;
14

15
  a.foo( 5 );
16
}

macht der Compiler konzeptionell für sich
1
struct A
2
{
3
  int i;
4
};
5

6
void A_foo( struct A* this, int j )
7
{
8
  this->i = j;
9
}
10

11
int main()
12
{
13
  struct a;
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.
#1307066
Lesenswert?

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
#1307076
Lesenswert?

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=( const T& 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.
#1307085
Lesenswert?

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!
#1307087
Lesenswert?

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.
#1307096
Lesenswert?

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=( const String & rhs )
2
{
3
  if( &rhs != this ) {
4
    delete [] pointer;
5
    pointer = new char [ strlen( rhs.pointer ) + 1 ];
6
    strcpy( pointer, rhs.pointer );
7
  }
8

9
  return *this;
10
}

die korrekte Version ist
1
String& String::operator=( const String & rhs )
2
{
3
  char * tmp = new char [ 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.
#1307100
Lesenswert?

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.
Gast #1307104
Lesenswert?

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
#1307115
Lesenswert?

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.
Gast #1307129
Lesenswert?

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
#1307132
Lesenswert?

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 = new char [ 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.
Gast #1307147
Lesenswert?

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
#1307152
Lesenswert?

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.
#1307158
Lesenswert?

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.
Gast #1307185
Lesenswert?

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
#1307333
Lesenswert?

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.
#1307434
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren