Const correctness mit std::unique_ptr



  • Hallo Forum,

    ich habe gerade ein Problem mit const correctness und std::unique_ptr.

    Hier mal mein Code:

    #include <memory>
    
    struct Resource {};
    
    class Widget {
    public:
    	Widget() : mResource(std::make_unique<Resource>()) {}
    	void doStuff() {}
    	const Resource& getResource() const { return *mResource; }
    private:
    	std::unique_ptr<Resource> mResource;
    };
    
    void doSomething(const std::unique_ptr<Widget>& widget) {
    	auto res = widget->getResource();
    	// mach was mit res
    
    	widget->doStuff();	// soll eigentlich nicht gehen
    }
    
    void application() {
    
    	auto widget = std::make_unique<Widget>();
    	doSomething(widget);
    }
    

    Ich möchte, dass der Aufruf widget->doStuff() in Zeile 18 zu einer Fehlermeldung des Compilers führt, weil die Funktion doSomething nichts am Widget verändern soll.

    Ich habe daher diese Funktionssignatur ausprobiert:

    void doSomething(const std::unique_ptr<const Widget>& widget);
    

    Das hat mir aber eine Fehlermeldung für Zeile 24 eingebracht:

    VS2013 schrieb:

    1>cppforum\source.cpp(24): error C2664: 'void doSomething(const std::unique_ptr<const Widget,std::default_delete<_Ty>> &)' : cannot convert argument 1 from 'std::unique_ptr<Widget,std::default_delete<Widget>>' to 'const std::unique_ptr<const Widget,std::default_delete<_Ty>> &'
    1> with
    1> [
    1> _Ty=const Widget
    1> ]
    1> Reason: cannot convert from 'std::unique_ptr<Widget,std::default_delete<Widget>>' to 'const std::unique_ptr<const Widget,std::default_delete<_Ty>>'
    1> with
    1> [
    1> _Ty=const Widget
    1> ]
    1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

    Der Compiler sieht keine Möglichkeit ein Widget-Objekt in ein const Widget-Objekt umzuwandeln.

    Wie löse ich dieses Problem am besten?
    Überladen möchte ich die Funktion eigentlich nicht, damit der Anwender bereits an der Signatur erkennt, das sein Widget nicht geändert wird.
    Gibt es dafür eine best practice?

    Vielen Dank und viele Grüße
    Matze



  • Wenn keine Verschiebung von Widget des Besitzes benötigt wird, einfach als const Referenz - wie früher. 😉

    void doSomething(const Widget& widget)
    {
      // ..
    }
    
    void application()
    {
      auto widget = std::make_unique<Widget>();
      doSomething(*widget);
    }
    

    Von Herb Sutter gab es dazu mal einen guten Talk.

    // edit
    Hier noch der Talk von Herb Sutter: https://www.youtube.com/watch?v=xnqTKD8uD64



  • Ja mist, jetzt habe ich zuviel gekürzt 🙄

    Eigentlich ist Widget nur eine Basisklasse und die Funktion hat als Parameter einen

    const std::vector<std::unique_ptr<Widget>>&
    

  • Mod

    MatzeHHC schrieb:

    Wie löse ich dieses Problem am besten?

    Indem du es dir gar nicht erst schaffst?
    unique_ptr als Funktionsargument ist nur sinnvoll, wenn Ownership tatsächlich übertragen werden soll.
    Für einen const unque_ptr<..>& - Funktionsparameter fällt mir kein sinnvoller Anwendungsbereich ein.

    Ein einfaches const Resource& oder const Resource* wäre hier angebracht.



  • MatzeHHC schrieb:

    Ja mist, jetzt habe ich zuviel gekürzt 🙄

    Eigentlich ist Widget nur eine Basisklasse und die Funktion hat als Parameter einen

    const std::vector<std::unique_ptr<Widget>>&
    

    Da könntest du boost::indirect_iterator verwenden und an die doSomething(..) -Funktion ein Iterator-Paar übergeben.



  • ok, danke


Anmelden zum Antworten