Funktion soll unique_ptr<T> und T* nehmen koennen



  • Hallo Leute.

    Ich habe eine Member-Funktion setType() die sowohl Type* als auch unique_ptr<Type> als Parameter nehmen koennen soll.

    Da das etwas kompliziert zu erklaeren ist, hier ein bisschen Code:

    class Variable {
    private:
      unique_ptr<Type> type;
    
    public:
      void setType(Type* type) {
        this->type.reset(type);
      }
    
      void setType(unique_ptr<Type>& type) {
        this->type = move(type);
      }
    };
    

    So sieht das ganze aktuell aus (stark vereinfacht natuerlich).

    Gibt es eine Moeglichkeit beide setTypes zu einer Funktion zu machen oder ist das nicht moeglich? Prinzipiell will ich dem User ermoeglichen einen eigenen Deleter anzugeben und aber gleichzeitig will ich ein setType(new Type()); erlauben, da dass wohl in 99% der Faelle exakt das ist was der User machen will.

    Deshalb die Frage ob das einfacher geht als alle set-Funktionen doppelt zu schreiben?



  • Wo ist der Vorteil von new gegenüber make_unique?



  • Eigene Deleter geht sowieso nicht ohne das es im Typ vom unique_ptr auftaucht. Im Gegensatz zu shared_ptr gibt es bei unique_ptr kein Type Erasure.



  • Aber wenn du einen userdef-Deleter zulassen willst, dann musst du beachten, dass das Teil der unique_ptr-Klasse ist. Nicht wie bei shared_ptr, wo der Deleter nicht zum Klassentyp gehört. Du müsstest also sogar ein template für deine unique_ptr-akzeptierende Funktion machen.

    Mir ist es auch unangenehm, einen unique_ptr& als Parameter zu haben, von dem in der Funktion weggemoved wird. Ich würds besser finden, wenn das setXXX uptr&& statt uptr& als Signatur hätte und man das move explizit machen müsste. Oder halt ein rvalue wir make_unique übergeben (das kompiliert auch nicht mit einfach-&).



  • Man kann sehr wohl eigene Deleter bei unique_ptr angeben, die muessen nur der selben Signatur entsprechen. Insofern muss auch setType kein template sein, ich muss nur die Deleter Signatur oeffentlich machen, das ist alles. Und ein void()(Type) ist da wirklich nicht sonderlich spannend und kompliziert zu nutzen.

    Meine Frage ist aber: kann ich eine Funktion haben die sowohl Type* als auch unique_ptr<Type> nimmt?

    Ich will logischerweise dem User nicht ueberall zu einem make_unqiue zwingen, denn den User interessiert es ja in 99% der Faelle gar nicht ob ich unqie_ptr, shared_ptr oder sonstwas verwende. Nur die paar Poweruser die einen eigenen Deleter wollen, die brauchen das.



  • New sollte die absolute Ausnahme sein. D.h., make_unique wäre der gewöhnliche Fall.



  • manni66 schrieb:

    New sollte die absolute Ausnahme sein. D.h., make_unique wäre der gewöhnliche Fall.

    Nein!

    Ich weiss gar nicht wo ich anfangen soll zu erklaeren warum das bullshit ist.
    Und nein, ich will da jetzt nicht darueber diskutieren, mach einfach einen eigenen Thread auf.



  • Shade Of Mine schrieb:

    mach einfach einen eigenen Thread auf.

    Warum, ich habe kein Problem.


  • Mod

    Shade Of Mine schrieb:

    manni66 schrieb:

    New sollte die absolute Ausnahme sein. D.h., make_unique wäre der gewöhnliche Fall.

    Nein!

    Doch.



  • Shade Of Mine schrieb:

    manni66 schrieb:

    New sollte die absolute Ausnahme sein. D.h., make_unique wäre der gewöhnliche Fall.

    Nein!

    Ich weiss gar nicht wo ich anfangen soll zu erklaeren warum das bullshit ist.

    Wäre aber interessant. Weil ich auch nicht ganz nachvollziehen kann wieso das so sein sollte.

    Ich finde auch ehrlich gesagt eine Schnittstelle der man einen rohen Zeiger übergibt, die dann einfach Besitz davon übernimmt, gelinde gesagt suboptimal.
    Wobei ich auch die normale Referenz bei deinem unique_ptr Setter suboptimal finde. Ich würde da eher nen by-value oder && Parameter erwarten.

    Und wenn du - trotzdem es eigentlich nix bringt und nur potentiell Verwirrung stiftet - dem User die Möglichkeit geben willst einen rohen Zeiger zu übergeben, dann mach eben einfach zwei Funktionen - der Konstruktor von unique_ptr ist nicht umsonst explicit .

    Bzw. wenn du unbedingt unbedingt willst ... mach halt ne Hilfsklasse die zwei implizite conversion constructors hat - einen für rohe Zeiger und einen für unique_ptr . Die Hilfsklasse verwendest du als Parameter. Die Implementierung sollte straight forward sein - die Hilfsklasse hat nen unique_ptr als Member und hat dann eine "consume" Funktion mit der man ne && auf dieses Member bekommt.
    ->

    class Variable {
    private:
      unique_ptr<Type> type;
    
    public:
      void setType(crazy_ptr<Type> type) {
        this->type = type.consume();
      }
    };
    

    Das wäre meiner Meinung nach aber die schlechteste denkbare Varinate. Weil halt eben crazy. Übelste POLA Verletzung.



  • angst essen seele auf



  • hustbaer schrieb:

    Wäre aber interessant. Weil ich auch nicht ganz nachvollziehen kann wieso das so sein sollte.

    Dann mach einen eigenen Thread auf.

    Aber OK, ich habe gelernt dass was ich will nicht geht. Danke. Dann also 2 Funktionen.

    Nächste Mal Frage ich bei Stackoverflow.



  • #include <memory>
    #include <utility>
    
    class Type {};
    
    template <typename T>
    struct TypeTraits {};
    
    template <>
    struct TypeTraits<std::unique_ptr<Type>>
    {
        static std::unique_ptr<Type> get_unique_ptr(std::unique_ptr<Type> value)
        {
            return value;
        }
    };
    
    template <>
    struct TypeTraits<Type*>
    {
        static std::unique_ptr<Type> get_unique_ptr(Type* value)
        {
            return std::unique_ptr<Type>(value);
        }
    };
    
    class Variable
    {
    public:
        template <typename T>
        void setType(T type)
        {
            m_type = TypeTraits<T>::get_unique_ptr(std::move(type));
        }
    
    private:
        std::unique_ptr<Type> m_type;
    };
    
    int main()
    {
        Variable variable;
        variable.setType(new Type());
        variable.setType(std::make_unique<Type>());
    }
    

    Ob das allerdings einfacher ist, bezweifle ich, hängt aber von deinem Kontext ab. Der Nachteil, dass Variable::setType(..) für Type* unsichtbar den Besitz übernimmt, bleibt natürlich bestehen.

    Hinweis: std::make_unique<..>(..) muss ggf. durch eine eigene Variante ersetzt werden.



  • @Shade Of Mine
    Deine Reaktion ist kindisch.

    Und davon abgesehen davon dass ich es für üblen Quatsch halte hab ich dir gezeigt wie es geht. Interessant also dass du "gelernt hast dass es nicht geht".

    Shade Of Mine schrieb:

    Nächste Mal Frage ich bei Stackoverflow.

    Ja, gerne.
    Dieses kindische "ich mach [was dummes], aber zu erklären warum das in Wirklichkeit gar nicht dumm is is mir echt zu blöd" ist auch nicht so spannend.



  • volkard schrieb:

    angst essen seele auf

    Was meinst du damit?
    Auf wen/was beziehst du dich?

    Wenn du verstanden werden willst musst du da denke ich schon etwas spezifischer sein.


  • Mod

    hustbaer schrieb:

    volkard schrieb:

    angst essen seele auf

    Was meinst du damit?
    Auf wen/was beziehst du dich?

    Mach dafür bitte einen eigenen Thread auf.



  • Und auch das ist für mich nicht klar.
    Meinst du er bezieht sich auf das "Mach dafür bitte einen eigenen Thread auf."?
    Oder ist das "Mach dafür bitte einen eigenen Thread auf." eine Erwiderung auf meine Frage (heisst: ich solle einen eigenen Thread für die Frage aufmachen)?



  • hustbaer schrieb:

    Dieses kindische "ich mach [was dummes], aber zu erklären warum das in Wirklichkeit gar nicht dumm is is mir echt zu blöd" ist auch nicht so spannend.

    Kann ich aber teilweise gut nachvollziehen. Ich stell hier ganz selten Fragen, und da überleg ichs mir auch immer zweimal, ob ich die wirklich stellen soll. Weil das tatsächlich öfter mal "dumm" rüberkommen mag, aber einfach viel zu viel dranhängt, um das irgendwie erklären zu können. Einfach weil man jahrelang mit dutzenden Kollegen an einer riesigen Software arbeitet, an der insgesamt schon seit Jahrzehnten gearbeitet wird und da einfach sehr vieles so ist wie es halt ist oder man sehr viel Kontextwissen braucht, um zu verstehen, warum etwas so ist. Und dann kommt hier so gut wie immer als Antwort "ist nicht gut, erklär mal genau, was du willst". Kann ich zwar auch gut verstehen, aber das geht halt oft einfach nicht.



  • Ich weiss was du meinst. Geht mir ja selbst manchmal ähnlich wie das was du beschreibst. Ist aber auf diesen Thread hier mMn. nicht anwendbar.

    Guck dir mal diesen Beitrag von Shade in diesem Thread an: https://www.c-plusplus.net/forum/p2493614#2493614

    Es geht hier also nicht darum dass es irgendwas spezielles zu bedenken gibt was man erklären müsste, sondern dass Shade einfach der Meinung ist dass ein (mMn. völlig berechtigter) Einwand generell Bullshit ist.

    Er schreibt auch nicht "darum geht's mir jetzt nicht, ich möchte einfach die Frage beantwortet haben". Und auch nicht "ich bin anderer Meinung". Er schreibt "das ist Bullshit aber ich hab keinen Bock zu erklären warum" (sinngemäss).
    (EDIT: Ich glaube auch nicht dass Shade das einfach nur ungünstig formuliert hat. Ich glaube dass er genau das gemeint hat was er geschrieben hat. Und so lange wie ich hier schon aktiv bin und diverse Beiträge von diversen Usern lese, bin ich mir auch ausreichend sicher dass meine Einschätzung da ins Schwarze trifft. /EDIT)

    Und dann hab' ich keinen Bock das kommentarlos stehen zu lassen. Weil es stur ist und schon ein wenig arrogant rüberkommt.

    Davon abgesehen hab' ich sehr wohl auf seine Frage geantwortet - also darauf was er eigentlich wissen wollte. Hat er mit keinem Wort auch nur zur Kenntniss genommen. Falls meine Antwort Blödsinn ist kann er das ja schreiben. Ich bin zwar nicht immer der freundlichste, aber ich habe nicht den Eindruck dass ich extrem stur sei und/oder nie einsehen würde wenn ich Unrecht hatte. Falls meine Antwort grundsätzlich "richtig" ist, aber für ihn nicht anwendbar bzw. nicht das was er sich vorgestellt hat kann er das auch gerne sagen.

    Statt dessen kommt aber folgende mMn. doch etwas kindische Reaktion:
    https://www.c-plusplus.net/forum/p2493635#2493635

    Verstehst du jetzt was ich meine und warum ich reagiert habe wie ich reagiert habe?



  • hustbaer schrieb:

    Verstehst du jetzt was ich meine und warum ich reagiert habe wie ich reagiert habe?

    ICH hatte kein Problem mit deiner Reaktion 😉 Ich wollte nur den anderen Punkt kommentieren, weil ich finde, dass es tatsächlich öfter mal ein Problem ist (nicht konkret auf diesen Thread bezogen) und diese Medaille zwei Seiten hat.


Log in to reply