Regel der großen 3 auch bei Referenzmembern gültig?
-
Hallo,
ich habe ein paar Klassen mit nicht-statischen Referenzen auf andere Datenmember. Quasi sowas wie Aliase:class Foo{ int member; int &alias; Foo():alias(member){} }Für solche Klassen braucht man anscheinend eigene Kopieroperationen, der Compiler hat sich jedenfalls beschwert, dass er selbst keine erstellen kann und das ist ja auch ganz nachvollziehbar, da er nicht weiß, worauf die neue Referenz zeigen soll. Kein Problem, habe ich gemacht.
Nun erinnere ich mich natürlich noch dunkel an die Regel der großen 3, dass ich wahrscheinlich auch einen eigenen Destruktor bräuchte. Gehe ich Recht in der Annahme, dass dies eine der Ausnahmen von der Regel ist? Denn der Speicher wird ja richtig freigegeben wenn member zerstört wird.Will nur auf Nummer sicher gehen, dass ich nichts übersehen habe.
-
Das hat eigentlich nicht viel mit den Grossen Drei zu tun. Was bei Referenzmembern nicht geht, ist ein defaultgenerierter Zuweisungsoperator. Die anderen beiden verhalten sich ganz normal (Referenzen können schliesslich erzeugt (kopiert) und zerstört werden, aber nicht zugewiesen). Den
operator=kriegst du auch selber nicht "direkt" hin. Um die Zuweisungssemantik sinnvoll zu implementieren, sind Zeiger wohl das Naheliegendste.
-
Also ist es wie ich es mir dachte und die Regel gilt hier nicht.
Ich bin mir nicht sicher, was du mir mit den anderen Sachen sagen wolltest, es ist kein Problem, operator= zu implementieren und den Kopierkonstruktor brauchte ich für die von mir gewünschte Funktionsweise, damit die Referenzen auch auf das neue Element zeigen:
class Foo { public: int member; int &alias; Foo(int i=0):alias(member), member(i){} Foo(const Foo& ref):alias(member), member(ref.member){} const Foo& operator=(const Foo& ref) { member=ref.member; } }; int main(){ Foo a(3); Foo b(a); a.member=5; cout<<a.member<<a.alias<<endl; // 55 cout<<b.member<<b.alias<<endl; // 33 }So will ich's auch haben.
Falls es jemanden interessiert, warum ich sowas mache: Ich überliste damit eine andere Funktion, die zwei bestimmte unabhängige Elemente gleicher Art in der Klasse erwartet. Dadurch, dass die beiden Elemente jetzt auf das selbe Element verweisen, entstehen die von mir gewünschten Effekte.
-
Schalt mal die Warnungen ein. Die Reihenfolge der Elemente, wie sie deklariert werden stimmen nicht mit der Reihenfolge in der Initialisierungsliste überein. Das könnte böse Überraschungen geben.
Elemente, welche Referenzen bzw Zeiger auf andere Elemente sind, sind fehleranfällig, wenn's ums Kopieren und Zuweisen geht. Die 3er-Regel sagt auch nicht, dass man immer die drei Funktionen definieren muss, wenn man eine definiert hat. Sie besagt nur, dass es sehr wahrscheinlich ist, dass man die anderen zwei Funktionen auch braucht. In Deinem Fall reicht eigener Copy-C'tor und Assignment-Operator.
Die bessere Alternative wäre aber, statt der anderen Klasse Zugriff auf Elemente zu gewähren und eigene copy/assignment Funktionen zu schreiben, einfach zwei Funktionen zu definieren, die einem die "logischen" Elemente zurückgeben. Die andere Klasse kann dann einfach diese Funktionen aufrufen -- ganz ohne Referenz-Hack.
Gruß,
SP
-
Nexus schrieb:
Den
operator=kriegst du auch selber nicht "direkt" hin. Um die Zuweisungssemantik sinnvoll zu implementieren, sind Zeiger wohl das Naheliegendste.In seinem Fall bringt man das ganz einfach selbst hin, nämlich indem man die Referenzen im Assignment Operator einfach nicht angreift. Sind ja nur Aliase auf andere Member, von daher müssen die nicht verändert werden.
-
die reihenfolge der initialisierung ist in diesem speziellen fall egal.
man greift ja nicht auf den wert zu, man definiert nur eine ref darauf.warum du aber damit eine funktion überlisten willst ?!
erklär mir das mal. die funktion merkt dann das doch dass die addressen gleich sind?
-
helfer schrieb:
warum du aber damit eine funktion überlisten willst ?!
erklär mir das mal. die funktion merkt dann das doch dass die addressen gleich sind?
Huh? Warum sollte eine Funktion sowas prüfen? Nein, es handelt sich um eine Reihe einfache Rechenfunktionen, die auf beiden Elementen etwas machen.
Und das ist nicht nur ein fauler Trick sondern ist auch in der Natur dessen begründet, was die Klassen darstellen sollen. Denn bei dem was die Klassen darstellen bezeichnen beide Elemente im Allgemeinen etwas unterschiedliches, aber es gibt halt ein paar Klassen von Spezialfällen wo beide Elemente nur unterschiedliche Bezeichnungen für das gleiche sind.
Ich fürchte der vorherige Absatz war ziemlich unverständlich
, aber mir fällt gerade keine gute Analogie ein und das konkrete Problem wäre zu lang zu beschreiben. Es bleibt wohl nur zusammenzufassen, dass diese Klassenstruktur das Modell perfekt beschreibt.edit: Ahh, mir ist eine Analogie eingefallen (zugegeben: weit hergeholt, aber passend): Die Funktion schlatet ein Radio ein und stellt eine Uhr um eine Stunde vor. Normalerweise enthält eine Klasse die man der Funktion gibt, ein bestimmtes Radio und eine bestimmte Uhr. Und jetzt soll aber ein Radiowecker an die Funktion übergeben werden, das heisst, Radio und Uhr sind nun ein und das selbe Objekt.
Ja, diese Funktionalität könnte man über Zeiger machen oder besser noch über die von Sebastian Pizer vorgeschlagenen Memberfunktionen. Die Funktion ist jedoch nicht durch mich änderbar und greift direkt auf die Elemente zu, wodurch sie inkompatibel zur Syntax von Zeigern und Memberfunkionen ist, aber bei Referenzen ändert sich ja nichts.
-
@SeppJ: Ich schätze das ganze wäre über Getter-Funktionen sauberer zu lösen.