Const-Correctness Problem
-
Hi, wer kann mir einen Design Tipp für folgendes Problem geben. Ich habe eine ItemsWidget Klasse die eine WidgetCollection besitzt in der alle Child-Widgets abgelegt werden. Da diese Liste wissen muss wer der Owner ist, bekommt sie das ParentWidget als Weak-Pointer übergeben. Die Collection wird dynamisch von der Function "EnsureItemCollection" erzeugt. Diese gibt es sowohl als const und nicht const. Das Problem was sich daraus ergibt ist die Const-Corectness. Denn die WidgetCollection nimmt nur nicht "const" Widget-Zeiger im Konstruktor an. Allerdings wird in der const EnsureItemCollection ein const SharedPtr übergeben. Jemand eine Idee wie man das elegant lösen könnte?
class WidgetCollection : public Object { public: ItemCollection(const SharedPtr<Widgets::ItemsWidget>& parent); SharedPtr<Widgets::ItemsWidget> _parent; Collections::Generic::List<SharedPtr<Object>> _items; }; class ItemsWidget : public Widget { public: ItemsWidget(); SharedPtr<WidgetCollection>& Items(); const SharedPtr<WidgetCollection>& Items() const; SharedPtr<ItemsWidget> SharedFromThis() { ... }; SharedPtr<const ItemsWidget> SharedFromThis() const { ... }; private: SharedPtr<WidgetCollection> _items; }; void ItemsWidget::EnsureItemCollection() { if (!_items) { _items = new WidgetCollection(SharedFromThis()); } } void ItemsWidget::EnsureItemCollection() const { if (!_items) { _items = new WidgetCollection(SharedFromThis()); } }
-
Ich würde folgendermaßen vorgehen:
- Die const EnsureItemCollection() verändert das Objekt - sollte daher besser gar nicht existieren.
- Die non-const EnsureItemCollection() ebenfalls entfernen - dafür ist ja der Konstruktor da.
- Die SharedPtr-Indirektion von _items scheint mir erstmal keinen Sinn zu machen, da ich hier keinen geteilten Besitz sehe - also durch normales Member ersetzen.
- In Items() eine Kopie der Liste zurückgeben und nicht eine Referenz. Die großzügige Verwendung von SharedPtr sieht so aus, als würdest du das alles gerne thread-safe haben (dafür brauchst du aber mindestens noch einen Mutex), das machst du dir aber wieder kaputt, wenn du Referenzen auf interne Member nach außen gibst.
- Anschließend stellt sich noch die Frage, ob eine Liste wirklich ihren Besitzer kennen muss. Würde ich ohne Kenntnis der Situation erstmal eher mit "nein" beantworten.
Also etwa so:
class ItemsWidget : public Widget { public: ItemsWidget() : _items(this) {...} WidgetCollection> Items() const {return _items;} private: WidgetCollection _items; };