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:

    1. Die const EnsureItemCollection() verändert das Objekt - sollte daher besser gar nicht existieren.
    2. Die non-const EnsureItemCollection() ebenfalls entfernen - dafür ist ja der Konstruktor da.
    3. Die SharedPtr-Indirektion von _items scheint mir erstmal keinen Sinn zu machen, da ich hier keinen geteilten Besitz sehe - also durch normales Member ersetzen.
    4. 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.
    5. 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;
    };
    

Anmelden zum Antworten