Zeiger oder Referenz?
-
Ich sehe die groessere Sicherheit mit Referenzen schon, aber ich persoenlich habe immer mit Zeigern gearbeitet, da eine Referenz in der letzten Instanz doch nur "an alternative name for an object" ist. Ich persoenlich arbeite dann lieber mit einem Pointer auf das Object, den ich auch NULL setzen kann, falls dieser nicht gesetzt sein sollte oder konnte.
Den tieferen Sinn des Copy-Konstruktors habe ich auch nie eingesehen - zumindest nicht bei nicht-trivialen Klassen. Wenn zwei oder mehr Instanzen einer Klasse benotige, die die gleichen Daten enthalten oder sich nur unwesentlich unterscheiden, dann baue ich eher eine weitere Klasse, die die gemeinsamen Daten beinhalten und lasse einen Pointer als Member der Klasse auf die Klasse mit den gemeinsamen Daten zeigen.
Aber das ist keine dogmatische Erklaerung, das ist mein Stil C++ zu schreiben.
-
Vertexwahn schrieb:
FireFlow schrieb:
- man spart sich wie bei Pointern den Cpy C'tor.
verstehe ich nicht - warum spart man sich den?
Naja bei Built-In Types ist es ja kein Problem, da soll es sogar schneller sein wenn by-value übergibt. Ist doch klar dass wenn man eine Referenz auf eine Klasse übergibt da kein CopyConstructor aufgerufen werden muss weil gar nix kopiert wird. Bei by-value wird ja eine lokale Variable erstellt. Bei einer Container-Klasse ist das weniger gut

Gruß
-
@fireflow
das kannst Du mit zeigern genauso mache. Ein Copy-Ctor ist da um etwas zu kopieren. Wenn du kopieren willst/musst, hilft Dir ne Referenz nicht, d.h. die Aussage, dass man sich mit Referenzen den Copy-Ctor spart ist falsch oder zumindest sehr missverständlich.Den tieferen Sinn des Copy-Konstruktors habe ich auch nie eingesehen - zumindest nicht bei nicht-trivialen Klassen. Wenn zwei oder mehr Instanzen einer Klasse benotige, die die gleichen Daten enthalten oder sich nur unwesentlich unterscheiden, dann baue ich eher eine weitere Klasse, die die gemeinsamen Daten beinhalten und lasse einen Pointer als Member der Klasse auf die Klasse mit den gemeinsamen Daten zeigen.
Es ist schon ein semantsicher Unterschied, ob Du zwei Objekte hast, oder ein Objekt mit zwei Referenzen darauf. Wenn Du ein Backup machst, ziehst Du auch nicht einfach ne Verknüpfung auf die CD. Du brauchst ne Möglichkeit einen String zu kopieren. Ok, in Java gibts da dann halt ne spezielle Kopier-Methode. Aber mit dem Copy-Ctor kannst Du's halt so machen, dass es sich bei allen Typen gleich 'natürlich' anfühlt, wie bei nem integer.
Ich persoenlich arbeite dann lieber mit einem Pointer auf das Object, den ich auch NULL setzen kann, falls dieser nicht gesetzt sein sollte oder konnte.
Dafür nehm ich zwischenzeitlich boost::optional. Zeiger da, wo sich das referenzierte Objekt ändern kann (z.B. pFreundin
), es aber immer eines gibt (also doch nicht pFreundin
).In Verbindung mit dynamischen Objekten nimmt man am besten keine nackten Zeiger, sondern smart-Pointer.
Also:
Das zu referenzierende Objekt ändert sich nicht -> Referenz
Das zu referenzierende Objekt kann sich ändern ist aber niemals unbelegt -> Zeiger
Das zu referenzierende Objekt kann unbelegt sein -> boost::optional
Es handelt sich um ein dynamisches Objekt, Gültigkeitsdauer und Besitzverhältnisse sind wichig -> entsprechenden smart-Pointer.
-
So am Rande: wem der Sinn von Referenzen nicht schlüssig ist sollte sich mal etwas Zeit nehmen und nen richtiges C++ Buch durchlesen.
-
kartoffelsack schrieb:
Den tieferen Sinn des Copy-Konstruktors habe ich auch nie eingesehen - zumindest nicht bei nicht-trivialen Klassen. Wenn zwei oder mehr Instanzen einer Klasse benotige, die die gleichen Daten enthalten oder sich nur unwesentlich unterscheiden, dann baue ich eher eine weitere Klasse, die die gemeinsamen Daten beinhalten und lasse einen Pointer als Member der Klasse auf die Klasse mit den gemeinsamen Daten zeigen.
Es ist schon ein semantsicher Unterschied, ob Du zwei Objekte hast, oder ein Objekt mit zwei Referenzen darauf.
Vielleicht war nicht ganz klar. Mal folgender Fall - eine einfache Bankkontenverwaltung:
class EinzelKonto { private: float iKontostand; //in Geldeinheiten int iKontoNr; //und noch mehr Daten zum Konto //Ab hier Daten zur Kontoart (Sparbuch, Giro, anlage ...) char *Bezeichnung; float fZinsatz; int iKuendigsfrirst; //und noch viel mehr //und hier div. Methoden .. }In jeden Object der Klasse Einzelkonto wiederholen sich Daten, die schon sehr viele Male verwendet wurde - damit wird jede Menge Heap verschwendet. In diesem Falle wuerde ich folgende Loesung machen:
class EinzelKonto { private: float iKontostand; //in Geldeinheiten int iKontoNr; //und noch mehr Daten zum Konto KontoTyp *pKontoTyp; } class KontoTyp { char *Bezeichnung; float fZinsatz; int iKuendigsfrirst; //und noch viel mehr //und hier div. Methoden .. }Sollte ein Konto keinem Typ zuzuordnen sein, so wuerde ein NULL-Pointer erscheinen. Das erspart jede Menge Speicher.
-
In Deinem Beispiel ist es schon schön und gut einen Zeiger zu verwenden (obwohl hier aus semantischer Sicht etwas wie boost::optional eigentlich schöner ist, weil NULL letzenendes auch nur irgendeine Magic-Number ist - aber immerhin eine so weit verbreitete, dass es nicht viel dagegen einzuwenden gibt. http://www.boost.org/libs/optional/doc/optional.html).
Ich hab mich aber auf Deinen Satz bezogen:
Den tieferen Sinn des Copy-Konstruktors habe ich auch nie eingesehen - zumindest nicht bei nicht-trivialen Klassen.
Ein Copy-Ctor hat bei allen Typen, ob trivial oder nicht einen Sinn, nämlich dann, wenn man das Objekt vervielfältigen kann und das hat nix mit ner Referenz zu tun (und der Konto-Typ wird natürlich nicht vervielfältigt, wenn ein neues Konto erzeugt wird, sondern das Konto ist einem aus n endlich vielen Typen zugeordnet). Das einzige, wo sich Copy-Ctor und Referenz 'überschneiden' und in gewisser Hinsicht austauschbar sind, ist beim Funktionsaufruf:
printKonto( const Konto& konto);
oder
printKonto( Konto konto);
Aber in Fall zwei ist es eben ein Konto, das dem orginalen gleicht, aber halt nicht ein und dasselbe Konta, wie es das in Fall 1 ist.
-
Zunaechst wuerde ich die Printfunktion einfach als Methode der EinzelKonto-Klasse definieren, aber davon abgesehen, was spricht dagegen es so zu machen:
EinzelKonto::EinzelKonto (EinzelKonto *pSource = NULL) { if (pSource == NULL) SetDefaults (); else { //Uebernimm Werte } }
-
was spricht dagegen es so zu machen
prinzipiell: dass das kopieren des Kontos eine andere Syntax hat als das Kopieren eines ints.
int zahl( andereZahl);
Konto( &anderesKonto);In Deiner Umsetzung: Dass das Orginal verändert werden kann, da ein const fehlt, dass Du Dein Objekt mit 'Konto konto();' initialisieren musst statt, wie man es normalerweise macht mit 'Konto konto;', dass Du keine Initialisierungslisten verwendest ...
Außerdem: Dein Beispiel ist auch eine Art Kopierkonstruktor, nur dass er nicht konventionell ist sondern halt nen Zeiger statt der const Ref kriegt. Du hingegen sagst
Den tieferen Sinn des Copy-Konstruktors habe ich auch nie eingesehen. Wenn zwei oder mehr Instanzen einer Klasse benotige, die die gleichen Daten enthalten oder sich nur unwesentlich unterscheiden, dann baue ich eher eine weitere Klasse, die die gemeinsamen Daten beinhalten und lasse einen Pointer als Member der Klasse auf die Klasse mit den gemeinsamen Daten zeigen
du meinst also, dass sich Copy-Ctor und Zeiger irgendwie ersetzen. Tun sie aber nicht. Sind völlig verschiedene Dinge.
-
kartoffelsack schrieb:
In Deiner Umsetzung: Dass das Orginal verändert werden kann, da ein const fehlt, dass Du Dein Objekt mit 'Konto konto();' initialisieren musst statt, wie man es normalerweise macht mit 'Konto konto;'
nein, Einzelkonto ist ja kein POD. Im übrigen ist dein Vorschlag eine Funktionsdeklaration.
-
nein, Einzelkonto ist ja kein POD. Im übrigen ist dein Vorschlag eine Funktionsdeklaration.
ok, sorry, einen Ctor mit Standard-Wert 'EinzelKonto::EinzelKonto (EinzelKonto *pSource = NULL)' kann/muss man offensichtlich mit 'Einzelkonto konto;' (also ohne '()') aufrufen. Ändert aber nix am Rest.