Missing clone_ptr / value_ptr
-
kurze_frage schrieb:
nachdem element_type und deleter_type vom unique_ptr bekannt sind ist das clone wenn gewollt eine freie Funktion die einmal entwickelt und dann für alle Objekte gilt die copy constructable sind,
'künstliche' clone Methoden werden unnütz.
Und das ist eigentlich, nach meinem Geschmack, eleganter.Als Template-Parameter bekannt ist beim Klonen ja nur der "static type". Klonen musst du aber den "dynamic type".
Dazu könnte man, analog dazu wasshared_ptr
für den Deleter macht, einen "Default-Kloner" beim Initialisieren/Resetten desclone_ptr
erzeugen und mit abspeichern. Dieser kann den dynamischen Typ klonen, da an dieser Stelle ja der dynamische Typ bekannt ist. Bzw. den Typ der ursprünglich an den Ctor bzw. die Reset-Funktion übergeben wurde.Das nächste Problem das man dabei hätte wäre dann: der Kloner kann nur einen Zeiger zurückgeben auf einen Typ
T
. Egal wie manT
wählt, sobald man Casts unterstützen will steht man vor dem Problem dass man irgendwann nenclone_ptr<U>
hat, der Kloner aber nenT*
zurückgibt. Dummerweise ist dabei aberT
demclone_ptr
nicht bekannt undU
dem Kloner nicht bekannt. Wei also den Zeiger konvertieren?Rein technisch würde ich sagen: sollte gehen. Man speichert einfach in jedem
clone_ptr
den Offset (inchar
s) zwischen dem gespeicherten Zeiger und dem originalenT*
(mitT
=dynamischer Typ des Objekts). Da der Kloner immerT*
zurückgibt, kann man dann aus einemclone_ptr<U>
einen weiterenclone_ptr<U>
klonen, indem man einfach den Offset auf den Rückgabewert des Kloners draufrechnet. Das würde dann sogar soweit funktionieren, dass man, wenn man einenclone_ptr<U>
auf das 27.U
-Subobjekt einesT
hat (dreaded diamond und so), und davon ausgehend klont, man als Ergebnis wieder einenclone_ptr<U>
auf das 27.U
-Subobjekt des neuenT
bekommt.Wo ich mir aber nicht so sicher bin ist ob der Standard Zeigerakrobatik dieser Art erlaubt.
-
Ich hatte mir mal einen smart pointer für copy-on-write gebastelt (
cow<T>
), dem ich auch Laufzeit-Polymorphie beibringen wollte (T durfte abstrakt sein, wobeicow<Derived>
dann incow<Base>
konvertierbar war), just for fun. Gebraucht habe ich das dann aber nie. Jedenfalls kann ich mich nicht dran erinnern, ihn tatsächlich eingesetzt zu haben. copy-on-write alleine ja. Aber nicht polymorph.
-
für den
clone_ptr
existiert bereits der Vorschlag N3339. Daraus ist aber anscheinend nichts geworden. Siehe noch hier http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3371.html) .. und danach ist er verschwunden.Ich habe einen
clone_ptr
bisher nie gebraucht.Gruß
Werner
-
Werner Salomon schrieb:
für den
clone_ptr
existiert bereits der Vorschlag N3339. Daraus ist aber anscheinend nichts geworden. Siehe noch hier http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3371.html) .. und danach ist er verschwunden.Ich habe einen
clone_ptr
bisher nie gebraucht.Gruß
Wernervielleicht ist der ja deswegen wieder verschwunden weil offensichtlich ist das wenn man value objects will soche auch verwenden sollte und auf dem heap herum kugelnde Objekte zum clonen doch sehr javaresk sind
-
Was aber nicht immer möglich ist. Hier ging es ja ganze Zeit um Polymorpie. Aber auch ohne kann es Sinn machen. Z.B. bei Datenstrukturen wie Linked Lists oder Bäumen. Wenn man die mit so einem
value_ptr
aufbauen würde braucht man sich nicht mehr um Copy Constructor kümmern.
-
sebi707 schrieb:
Aber auch ohne kann es Sinn machen. Z.B. bei Datenstrukturen wie Linked Lists oder Bäumen. Wenn man die mit so einem
value_ptr
aufbauen würde braucht man sich nicht mehr um Copy Constructor kümmern.Sehe nicht, wofür man dort einen solchen "
value_ptr
" brauchen würde. Was genau macht der, was einunique_ptr
dort nicht machen nicht kann?
-
@dot
Denvalue_ptr
bzw.clone_ptr
brauchst du wenn du Value-Semantik mit Polymorphie kombinieren willst.
-
Ist mir schon klar, nur angeblich soll der jetzt auch ohne Polymorphie was bringen und das versteh ich grad nicht!?
-
Das hat er doch gerade geschrieben, du musst den Copy-Ctor nicht implementieren.
StattFoo::Foo(Foo const& other) { if (other.m_left) m_left.reset(other.m_left->clone()); if (other.m_right) m_right.reset(other.m_right->clone()); }
schreibst du einfach ... nix.
Nix schreiben ist einfacher. Und weniger fehleranfällig.
-
Naja großartig, dann hast du deinen Copy C'tor halt
clone()
genannt, implementieren musst du es trozdem. Ich ging davon aus, dass es selbstverständlich ist, dass man, wenn man schon meint, so einclone()
Teil haben zu müssen, den Copy C'tor private oder protected implementiert (oder defaulted) und dannauto clone() const { return std::make_unique<Blub>(*this); }
macht, weil wieso würde man irgendwas anderes machen...
-
Nein du brauchst auch keine clone Funktion. Alle Membervariablen werden durch den Aufruf ihres Copy Constructors kopiert und der
value_ptr
implementiert diesen eben so, dass nicht die Adresse kopiert wird sondern tatsächlich die Daten. Wobei wir ja schon diskutiert haben das dieser Kopiervorgang für polymorphe Objekte nicht so einfach ist. Ohne Polymorpie ist das allerdings trivial.
-
Dafür brauch ich aber keinen
value_ptr
weil der Copy C'tor macht das doch schon!?
-
Aber falsch. Wenn du Raw Pointer benutzt kopiert er nur die Adressen und wenn du
unique_ptr
benutzt gibts gar keinen Default Copy Constructor weilunique_ptr
Move only ist.
-
nach dem ansehen von 'inheritance is the base class of evil' bin ich der Meinung das ich bis dahin immer viel zu viel polymorphe Objekte gebaut habe und deswegen alles so kompliziert wurde. Sean Parent legt da einfach seine value Objekte von unterschiedlichen Typen in den Container, sehr fesch die Methode!
Ansonst, mit nur einem Pointer auf die Base Klasse wird ohne weitere Info auch ein value_ptr Probleme haben irgendetwas brachbar zu kopieren, von selber geht da also nix.
-
sebi707 schrieb:
Aber falsch. Wenn du Raw Pointer benutzt kopiert er nur die Adressen und wenn du
unique_ptr
benutzt gibts gar keinen Default Copy Constructor weilunique_ptr
Move only ist.Die Frage ist, wieso willst du "Pointer kopieren"? Wenn dein Typ Wertsemantik hat und du besitzende Zeiger drauf hast, hast du sehr wahrscheinlich was falsch gemacht...
-
dot schrieb:
Naja großartig, dann hast du deinen Copy C'tor halt
clone()
genannt, implementieren musst du es trozdem. Ich ging davon aus, dass es selbstverständlich ist, dass man, wenn man schon meint, so einclone()
Teil haben zu müssen, den Copy C'tor private oder protected implementiert (oder defaulted) und dannauto clone() const { return std::make_unique<Blub>(*this); }
macht, weil wieso würde man irgendwas anderes machen...
Das wurde doch schon alles diskutiert: es sollte möglich sein dass der
value_ptr
den normalen Copy-Ctor verwendet.dot schrieb:
Dafür brauch ich aber keinen
value_ptr
weil der Copy C'tor macht das doch schon!?Wenn du mir zeigst wie du nen Baum oder ne verkettete Liste ohne Zeiger aufbaust...
-
hustbaer schrieb:
dot schrieb:
Dafür brauch ich aber keinen
value_ptr
weil der Copy C'tor macht das doch schon!?Wenn du mir zeigst wie du nen Baum oder ne verkettete Liste ohne Zeiger aufbaust...
Die Frage ist, wo ich dabei die Ziele irgendwelcher Pointer kopieren muss...
-
@dot
Meine Geduld wird gerade sehr strapaziert.Wie kopierste deinen Baum denn?
Wie meinste kopiert sichstd::set
?
Indem es Nodes kopiert, die Zeiger auf weitere Nodes haben, die auch wieder kopiert werden müssen usw.
-
Wenn ich einen Typen mit Wertsemantik hab, steck ich die Objekte direkt in den Container, weil wieso würde ich eine sinnlose Indirektion haben wollen!? Wenn ich Typen mit Referenzsemantik hab, mach ich mir lieber eine Funktion, die mir per
make_unique(**it)
eine Deep Copy anfertigt (denn das ist die einzige Stelle, an der ich das brauche), bevor ich solch fragwürdige Konstrukte wie einenvalue_ptr
in freie Wildbahn entlasse...
-
@dot
Vergiss vielleicht einfach mal den Begriff Zeiger.
Statt dessen denk anboost::optional
.
Wenn wir polymorphie mal aussen vor lassen, dann ist das Ding worüber wir reden einboost::optional
welches rekursive Datenstrukturen erlaubt.