Funktion soll unique_ptr<T> und T* nehmen koennen



  • 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.



  • hustbaer schrieb:

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

    Weil du staenkern willst, ist mir durch aus klar 🙂
    Und jetzt bist du eingeschnappt weil ich deine "Loesung" uebergangen habe.

    Aber das sind eben diese Trivialitaeten mit denen ich mich nicht wirklich befassen will: die Fragestellung war, geht es einfacher als alle set-Funktionen doppelt zu schreiben. Und da ist die Antwort ein klares: Nein. Und warum ich deinen "Beitrag" mit keiner Antwort gewuerdigt habe, erklaert sich wohl von selbst, oder? theta's Beitrag haette aber in der Tat ein Danke verdient. Also: Danke theta.

    Eine andere Trivialitaet ist, dass new nichts boeses ist. Wir sagen das Anfaengern gerne weil es gut ist sie davon abzuhalten new zu verwenden. Aber wenn man sich ein bisschen auskennt erkennt man schnell das new ansich kein Problem ist, das Problem ist delete und ownership.

    Mach einen eigenen Thread auf, dann erklaere ich dir vielleicht wie gutes API Design aussieht und warum man nicht die Implementierungsdetails komplett In-Your-Face ins Interface packt. (Schocker: Design Entscheidungen sind Abhaengig vom Kontext. 😮 Mind Blown, nicht wahr?)

    Ich kann mich aber nicht erinnern wann ich das letzte mal eine sinnvolle Antwort auf eine Frage bekommen habe. Jedesmal artet das in genau sowas aus, komplettes Offtopic, eine Infragestellung der Frage und dann sind Leute eingeschnappt.

    Alleine diese Diskussion hier bestaetigt doch nur was ich sage 🙂
    Und wenn du nicht nachgetreten haettest, haette ich diesen Beitrag auch nicht geschrieben. So viel zu kindisch 😉


  • Mod

    hustbaer schrieb:

    Und auch das ist für mich nicht klar.

    Das war eine Parodie auf Shade. 😉



  • Shade Of Mine schrieb:

    Weil du staenkern willst, ist mir durch aus klar 🙂

    Nein. Weil ich dich für überheblich und reichlich stur halte. Was du mit diesem Beitrag wieder bestätigst. Du weisst einfach alles besser, auch wenn du total daneben liegst.

    Shade Of Mine schrieb:

    Und jetzt bist du eingeschnappt weil ich deine "Loesung" uebergangen habe.

    Kommt drauf an was du damit meinst. Wenn du meinst dass ich eingeschnappt bin weil du so getan hast als ob ich überhaupt nichts zum Thema geschrieben hätte, dann ja. Weil ich das für unhöflich halte.

    Shade Of Mine schrieb:

    Aber das sind eben diese Trivialitaeten mit denen ich mich nicht wirklich befassen will: die Fragestellung war, geht es einfacher als alle set-Funktionen doppelt zu schreiben. Und da ist die Antwort ein klares: Nein. Und warum ich deinen "Beitrag" mit keiner Antwort gewuerdigt habe, erklaert sich wohl von selbst, oder?

    Nein, tut es nicht.
    Bei deiner Frage bin ich mal einfach davon ausgegangen dass du es nicht 1x oder 2x brauchst, sondern mehrfach. Weil die Frage ob man sich eine 1-zeilige Forwarding-Funktion sparen kann sonst irgendwie lächerlich ist.
    Und wenn man es mehrfach braucht würde ich sagen ist mein Vorschlag immer noch der kürzeste.

    Shade Of Mine schrieb:

    Eine andere Trivialitaet ist, dass new nichts boeses ist. Wir sagen das Anfaengern gerne weil es gut ist sie davon abzuhalten new zu verwenden. Aber wenn man sich ein bisschen auskennt erkennt man schnell das new ansich kein Problem ist, das Problem ist delete und ownership.

    Ja, genau, das Problem ist delete und Ownership. Und weil es naiv wäre anzunehmen, dass jeder, der Code liest welcher dein Interface verwendet, dein Interface in und auswendig kennt, ist es halt blöd wenn da einfach nur foo.setBar(new Bar()); steht. Weil man dann eben nicht sieht ob setBar die Ownership übernimmt oder nicht. Klar, wenn man nur verstehen will was abgeht und einfach mal davon ausgehen kann dass es passt ist das nicht schlimm. Wenn man Fehler sucht ist das aber sehr lästig. Hast du schonmal Fehler in Code von anderen Leuten gesucht? Wo du dir nicht sicher sein konntest ob die bestimmte Dinge verstanden bzw. sich darum geschert haben?

    Und auch beim Schreiben von Code ist es lästig wenn man immer wissen muss welche Funktionen Ownership übernehmen und welche nicht.

    Wenn setBar dagegen einen unique_ptr nimmt ist die Sache klar. Das spart Kopfschmerzen und verringert die Chance Schlampigkeitsfehler zu machen.

    Shade Of Mine schrieb:

    Mach einen eigenen Thread auf, dann erklaere ich dir vielleicht wie gutes API Design aussieht

    So viel zum Thema überheblich 🙄

    Shade Of Mine schrieb:

    und warum man nicht die Implementierungsdetails komplett In-Your-Face ins Interface packt.

    unique_ptr ist also ein Implementierungsdetail. Wow. Letztlich geht es um die Information "hier wird Ownership transferiert", und die sollte verdammtnochmal ins Interface. Weil die Doku kaum jemand liest. Und die wenigen Doku-Leser auch mal was überlesen oder vergessen. Wenn du der (mir unverständlichen) Meinung bist dass unique_ptr ein Implementierungsdetail sei, dann mach eine eigene Klasse dafür. Ist std::string für dich auch ein Implemeniterungsdetail?

    Oder ist dir vielleicht nicht bekannt dass es da eine Funktion
    http://en.cppreference.com/w/cpp/memory/unique_ptr/release
    gibt? Heisst: unique_ptr im Interface sagt nix darüber aus wie deine Library/Klasse/... das Objekt weiterhin verwalten wird. Es sagt nur: Ich übernehme Ownership. Und das ist ja wohl ganz klar kein Implemeniterungsdetail. Nichtmal wenn die Klasse dann intern wirklich unique_ptr verwendet. Mal ganz abgesehen davon dass du ja sowieso den 2. Overload mit unique_ptr hast. Der ja wohl auch zum Interface gehört. Womit das angebliche Implementierungsdetail sowieso schon im Interface ist.

    Und guck, jetzt hab ich dir was über API Design erzählt. Wow, Shocker.

    Shade Of Mine schrieb:

    (Schocker: Design Entscheidungen sind Abhaengig vom Kontext. 😮 Mind Blown, nicht wahr?)

    Uiiiii, danke für die Aufklärung.

    Shade Of Mine schrieb:

    ...

    Vielleicht artet es auch jedes mal wenn du eine Frage stellst so aus, weil du einfach so stur bist, und meinst alles besser zu wissen? Auch wenn dir mehrere erfahrene, gute Entwickler sagen dass sie ganz entschieden anderer Meinung sind?



  • ps:
    Die Variante von theta ist mM. unnötig kompliziert. Das selbe erreichst du mit

    class Variable 
    { 
    public: 
         template <typename T> 
         void setType(T&& type) 
         { 
             m_type = std::unique_ptr<Type>(std::forward<T>(type));
         } 
    
    private: 
         std::unique_ptr<Type> m_type; 
    };
    

    Und vom Prinzip her macht die Lösung nicht viel was anderes als was ich vorgeschlagen habe.

    Nur dass mit meiner Variante (die ursprüngliche, nicht die hier gezeigte forward -Sache) die setType Funktionen ... naja, kürzer werden. Und vor allem kein Template sein müssen. Also ganz klar dass meine Variante kein Wort aber die von theta ein Danke verdient.

    Bullshit.


Anmelden zum Antworten