facebook releases Folly, an open source C++ library



  • hustbaer schrieb:

    Dass du nicht verstanden hast was wir meinen? 🤡

    Höchstwahrscheinlich 🙄



  • Naja komm dein Beispiel ist Quatsch, und das solltest du auch wissen wenn du den letzten Beitrag von kk gelesen hättest.

    Klar geht das so wie du es zeigst, aber es bleibt trotzdem Quatsch, und es bietet vor allen keinerlei Sicherheit.

    void invoke(const pointer<fun>& ptr) {
        pointer<fun> p2 = ptr;
        p2.get()->print();
    }
    

    EDIT: OK, du zeigst die Variante wo get immer "T*" und nie "T const"* zurück gibt. Also geht es dort nicht, aber es geht eben so sowieso nicht. /EDIT

    Achja, hier die sinnvolle, funktionierende Variante:

    int main() 
    { 
         fun* f = new fun(); 
         pointer<fun const> p = f; 
         invoke(p); 
    }
    


  • Bloops schrieb:

    Nur warum veröffentlicht Facebook das?

    Weil sie viel auf Open Source setzen und viele ihrer Bibliotheken Open Source machen wollen. Warum auch nicht, wenn man von der Community gratis Bugfixes und neue Features bekommen kann. FB will wohl noch mehr ihrer Bibliotheken veröffentlichen, das ist nur der Anfang.

    http://herbsutter.com/2012/06/02/facebook-folly-oss-c-libraries/?utm_source=tf&utm_medium=t



  • Ich verstehe zwar grundsätzlich, worauf krümelkacker hinaus will und stimme auch zu, aber stimmt das hier wirklich:

    void foo(DiscriminatedPtr<int,double> const& x)
    {
      x.get_nothrow<int>(); // --> const int*
      auto y = x;
      y.get_nothrow<int>(); // --> int*
    }
    

    😕
    Wieso geht denn hier beim Kopieren die Constqualifizierung des Zeigers verloren?

    Edit: Ach ja. Ich bin ja so doof. Hat sich erledigt.



  • Tachyon schrieb:

    Ich verstehe zwar grundsätzlich, worauf krümelkacker hinaus will, aber stimmt das hier wirklich:

    void foo(DiscriminatedPtr<int,double> const& x)
    {
      x.get_nothrow<int>(); // --> const int*
      auto y = x;
      y.get_nothrow<int>(); // --> int*
    }
    

    😕
    Wieso geht denn hier beim Kopieren die Constqualifizierung des Zeigers verloren?

    const/nonconst-Überladung, analog zu dem hier:

    void bar(std::vector<int> const& v)
    {
      v.begin(); // --> const_iterator
      auto y = v; //std::vector<int>, ohne const!
      y.begin(); // --> iterator
      auto const z = v; //std::vector<int> const
      z.begin(); // --> ah, const_iterator!
    }
    

    😉



  • Ja. Bin inzwischen selbst drauf gekommen. Nachdenken hilft, wie bereits weiter oben geschrieben wurde.



  • hustbaer schrieb:

    Naja komm dein Beispiel ist Quatsch, und das solltest du auch wissen wenn du den letzten Beitrag von kk gelesen hättest.

    Natürlich ist es Quatsch, ich hab ja KK Rat befolgt und den Const-Q. entfernt!



  • Zeus schrieb:

    hustbaer schrieb:

    Naja komm dein Beispiel ist Quatsch, und das solltest du auch wissen wenn du den letzten Beitrag von kk gelesen hättest.

    Natürlich ist es Quatsch, ich hab ja KK Rat befolgt und den Const-Q. entfernt!

    Was daran nix ändert dass der Code Quatsch ist.

    Mit entferntem Const-Qualifizierer sieht man es bloss schneller.
    Mit nicht entferntem Const-Qualifizierer ist es deswegen aber nicht weniger Qutasch.



  • hustbaer schrieb:

    Zeus schrieb:

    hustbaer schrieb:

    Naja komm dein Beispiel ist Quatsch, und das solltest du auch wissen wenn du den letzten Beitrag von kk gelesen hättest.

    Natürlich ist es Quatsch, ich hab ja KK Rat befolgt und den Const-Q. entfernt!

    Was daran nix ändert dass der Code Quatsch ist.

    Mit entferntem Const-Qualifizierer sieht man es bloss schneller.
    Mit nicht entferntem Const-Qualifizierer ist es deswegen aber nicht weniger Qutasch.

    Was für ein Quatsch 🙄



  • Zeus, ich versteh' dich nicht. Es wurde nu schon ca. 3x erklärt warum die in DiscriminatedPtr implementierte Variante keinen Sinn macht.

    const T* ist eben nicht das selbe wie T* const .



  • hustbaer schrieb:

    Zeus, ich versteh' dich nicht. Es wurde nu schon ca. 3x erklärt warum die in DiscriminatedPtr implementierte Variante keinen Sinn macht.

    Ich seh keine Erklärungen.

    Wo besteht die Gemeinsamkeit zwischen den Code?

    template <typename... Types>
    class DiscriminatedPtr {
    
      template <typename T>
      const T* get_nothrow() const noexcept ...
    
      template <typename T>
      const T* get() const ...
    
    };
    
    #include <iostream>
    using namespace std;
    void wasbinich(const int&) {cout<<"const int\n";}
    void wasbinich(      int&) {cout<<"      int\n";}
    int main()
    {
      int i = 42;
      int*       p = &i;
      int* const q = &i;
      wasbinich(*p);
      wasbinich(*q);
    }
    

    hustbaer schrieb:

    const T* ist eben nicht das selbe wie T* const .

    Danke hustbaer genau so iss es!
    Das isst es!

    const int* q = &i;
      wasbinich(*q);
    

    krümelkacker schrieb:

    Da hat scheinbar jemand "const" nicht ganz verstanden; denn "const T*" bringt absolut gar nichts, da man den Zeiger ja kopieren kann

    IMO steht das Const nicht dafür da. Was ist daran so schlecht die Const Correctness auf das Objekt zu delegieren.

    #include <iostream>
    using namespace std;
    
    class fun {
    public:
        void print()       {    cout << "Side-effect";       }
        void print() const {    cout << "Side-effect free";  }
    };
    
    template<typename T> class pointer {
    public:
        pointer(T* ptr) : ptr(ptr) {}
        T* get() { return ptr; }
        T* get() const { return ptr; }
    private:
        T* ptr;
    };
    
    void invoke(const pointer<fun> ptr) {
        ptr.get()->print();
    }
    
    void invoke(const fun* ptr) {
        ptr->print();
    }
    
    int main()
    {
        fun* f = new fun();
        pointer<fun> p = f;
        invoke(p);
        invoke(f);
    }
    

    Den Entwickler, der die Pointer-Klasse sollte man liquidieren, hat der tatsächlich gewackt eine Klasse wie ein Sprachmittel zu bennen, dass sich garnicht so wie ein solches benimmt.



  • Zeus schrieb:

    IMO steht das Const nicht dafür da. Was ist daran so schlecht die Const Correctness auf das Objekt zu delegieren.

    Daran wäre gar nichts schlecht, wenn man es richtig machen würde, was hier aber nicht der Fall ist.

    Und falschrum macht es keinen Sinn. Es ist nicht intuitiv, man kann es leicht umgehen (ohne irgendwelche Casts) und man kann sich nichtmal darauf verlassen dass es nicht "unabsichtlich automatisch" umgangen wird.

    http://ideone.com/Nmm8s

    #include <iostream>
    using namespace std;
    
    class fun {
    public:
            void quack()       { cout << "mutable\n"; }
            void quack() const { cout << "const\n"; }
    };
    
    template<typename T> class broken_pointer {
    public:
            explicit broken_pointer(T* ptr) : ptr(ptr) {}
            T* get() { return ptr; }
            T const* get() const { return ptr; }
            T* operator -> () { return ptr; }
            T const* operator -> () const { return ptr; }
    private:
            T* ptr;
    };
    
    template<typename T> class good_pointer {
    public:
            template <typename U>
            explicit good_pointer(U* ptr) : ptr(ptr) {}
            template <typename U>
            good_pointer(good_pointer<U> const& ptr) : ptr(ptr.get()) {}
            T* get() const { return ptr; }
            T* operator -> () const { return ptr; }
    private:
            T* ptr;
    };
    
    template <typename DUCK>
    void invoke(DUCK d) {
            d->quack();
    }
    
    void test(fun const* native, fun* const reverse_native, const broken_pointer<fun> broken, good_pointer<const fun> good, const good_pointer<fun> reverse_good) {
            cout << "const T*     : "; invoke(native);
            cout << "T* const     : "; invoke(reverse_native);
            cout << "broken<const>: compiliert leider nicht, tjoah\n";
            cout << "const broken : "; invoke(broken);
            cout << "good<const>  : "; invoke(good);
            cout << "const good   : "; invoke(reverse_good);
    }
    
    int main(int /*argc*/, char** /*argv*/) {
            fun* native = new fun();
            test(native, native, broken_pointer<fun>(native), good_pointer<fun>(native), good_pointer<fun>(native));
            delete native;
    }
    

    Frage: was bringt der sog. "const support" in broken_pointer ?

    Meine Antwort: nix ausser Verwirrung. Also ganz weglassen, dann ist wenigstens klar dass die Klasse das nicht unterstützt. Bzw. nur teilweise, weil die Konvertierung von ptr<T> nach ptr<const T> nicht implizit unterstützt wird (explizit ist sie ja immer noch mit ptr<const T>(other.get()) möglich).

    Kannst du mir eine sinnvolle Anwendung dafür nennen? Wenn ja immer her damit, ich kann mir nämlich keine vorstellen.

    Den Entwickler, der die Pointer-Klasse sollte man liquidieren, hat der tatsächlich gewackt eine Klasse wie ein Sprachmittel zu bennen, dass sich garnicht so wie ein solches benimmt.

    Öhm...
    Also...
    Wenn du mir den Sinn des Verhaltens von const broken_pointer<T> erklären kannst, dann könnte man vielleicht anfangen darüber nachzudenken ob der Name klug gewählt ist. Wenn nicht, dann erübrigt sich mMn. die Diskussion, weil sinnlos eben sinnlos bleibt.



  • Vielleicht sollten wir beide eine neuen Auflage von Andrei Alexandrescu Modernes C++ Design lesen. Er kann bestimmt dir viel besser ConstPolicy für seine SmartPointer erläutern.

    ////////////////////////////////////////////////////////////////////////////////
    /// @note These policy classes are used in LockingPtr and SmartPtr to define
    ///  how const is propagated from the pointee.
    ////////////////////////////////////////////////////////////////////////////////[/
    template< class T > struct DontPropagateConst
    {
        typedef T Type;
    };
    
    template< class T > struct PropagateConst
    {
        typedef const T Type;
    };
    


  • Zeus schrieb:

    Vielleicht sollten wir beide eine neuen Auflage von Andrei Alexandrescu Modernes C++ Design lesen. Er kann bestimmt dir viel besser ConstPolicy für seine SmartPointer erläutern.

    ////////////////////////////////////////////////////////////////////////////////
    /// @note These policy classes are used in LockingPtr and SmartPtr to define
    ///  how const is propagated from the pointee.
    ////////////////////////////////////////////////////////////////////////////////[/
    template< class T > struct DontPropagateConst
    {
        typedef T Type;
    };
    
    template< class T > struct PropagateConst
    {
        typedef const T Type;
    };
    

    Das Ding beschreibt aber, wie das const von dem Ding, auf das gezeigt wird (eben der Pointee) weitergereicht wird. Mit der Constness des Pointers hat das nichts zu tun.



  • Tachyon schrieb:

    Das Ding beschreibt aber, wie das const von dem Ding, auf das gezeigt wird (eben der Pointee) weitergereicht wird. Mit der Constness des Pointers hat das nichts zu tun.

    Als Hilfestellung in welchen Fällen kann der SmartPointer die Constness auf dem Pointee weiterleiten?



  • Propagieren von const macht nur bei so Dingen wie copy_ptr oder unique_ptr Sinn. Und ratet mal warum: Diese Zeiger verhalten sich nicht wirklich wie Zeiger in dem Sinne, dass ich einen Zeiger kopieren kann, wobei sich die Kopie auf denselben Pointee bezieht. Man kann sie als Wrapper mit Wertesemantik betrachten.

    Zeus schrieb:

    Ich seh keine Erklärungen.

    Schade.

    Zeus schrieb:

    Wo besteht die Gemeinsamkeit zwischen den Code?

    template <typename... Types>
    class DiscriminatedPtr {
    
      template <typename T>
      const T* get_nothrow() const noexcept ...
    
      template <typename T>
      const T* get() const ...
    
    };
    
    #include <iostream>
    using namespace std;
    void wasbinich(const int&) {cout<<"const int\n";}
    void wasbinich(      int&) {cout<<"      int\n";}
    int main()
    {
      int i = 42;
      int*       p = &i;
      int* const q = &i;
      wasbinich(*p);
      wasbinich(*q);
    }
    

    Weil du da oben const T* geschrieben hast, gibt es leider nicht viele Gemeinsamkeiten. Du solltest hier erkannt haben, dass ein int* const dir Schreibzugriff auf den int gibt, genauso wie DiscriminatedPtr<int> const dir Schreibzugriff auf den int geben sollte, was allerdings die originale DiscriminatedPtr Implementierung und das, was du hier zeigst, aus irgendwelchen Gründen nicht tut. Dass diese Implementierung das nicht tut, stellt im übrigen keinen Gewinn dar, da du den Zeiger kopieren kannst, dadurch einen zweiten non-const Zeiger hast, der dann doch Schreibzugriff auf das int-Objekt erlaubt:

    DiscriminatedPtr<int> const q (&i);
    *q.get() = 42; // klappt bei dir nicht. Dieser "Schutz" bringt aber nichts weil...
    DiscriminatedPtr<int> p = q;
    *p.get() = 42; // Upps! Aufeinmal kann ich denselben!!! int doch verändern!!!
    

    Zeus schrieb:

    hustbaer schrieb:

    const T* ist eben nicht das selbe wie T* const .

    Danke hustbaer genau so iss es!
    Das isst es!

    const int* q = &i;
      wasbinich(*q);
    

    Dieses Beispiel hat mit gar nichts zu tun. Der Typ von q würde DiscriminatedPtr<const int> entsprechen, wir reden hier aber von DiscriminatedPtr<int> const . Bekomm das mal bitte auf die Reihe.

    Zeus schrieb:

    krümelkacker schrieb:

    Da hat scheinbar jemand "const" nicht ganz verstanden; denn "const T*" bringt absolut gar nichts, da man den Zeiger ja kopieren kann

    IMO steht das Const nicht dafür da. Was ist daran so schlecht die Const Correctness auf das Objekt zu delegieren.

    Es ergibt keinen Sinn, wie hier zum vierten mal erklärt!



  • Zeus schrieb:

    Als Hilfestellung in welchen Fällen kann der SmartPointer die Constness auf dem Pointee weiterleiten?

    Loki Lib schrieb:

    note These policy classes are used in LockingPtr and SmartPtr to define how const is propagated from the pointee.

    Siehst Du den Unterschied? Gruseligerweise propagiert der Code aber entgegen der Beschreibung die Constness des Pointers, und nicht die des Pointees.



  • Zeus schrieb:

    Findet ihr?

    #include <iostream>
    using namespace std;
    
    class fun
    {
    public:
    	void print() {
    		cout << "Side-effect";
    	}
    
    	void print() const {
    		cout << "Side-effect free";
    	}
    };
    
    template<typename T> class pointer
    {
    public:
    	pointer(T* ptr) : ptr(ptr) {
    
    	}
    	T* get() {
    		return ptr;
    	}
    
    	T* get() const {
    		return ptr;
    	}
    private:
    	T* ptr;
    };
    
    void invoke(const pointer<fun>& ptr) {
    	ptr.get()->print();
    }
    
    int main()
    {
    	fun* f = new fun();
        pointer<fun> p = f;
        invoke(p);
    }
    

    Und was soll das jetzt? Die Überladung von get ist da natürlich sinnfrei. Die non-const Version brauchst du nicht. Wenn Du nicht möchtest, dass invoke das fun-Objekt verändern kann, dann musst du es so deklarieren:

    void invoke(pointer<const fun> ptr)
    

    und der pointer Klasse eine entsprechende Konvertierung anbieten:

    template<typename T>
    class pointer
    {
    public:
        pointer(T* ptr)
        : ptr(ptr) {}
    
        template<class U>
        pointer(pointer<U> const& p,
            typename std::enable_if<
                std::is_convertible<U*,T*>::value
            >::type* =0)
        : ptr(p.get()) {}
    
        T* get() const {return ptr;}
        T* operator->() const {return ptr;}
        T& operator->() const {return *ptr;}
    private:
        T* ptr;
    };
    

    So verhält sich ein roher Zeiger.



  • Siehe übrigens auch Iteratoren, die ja auch eine Art Smartpointer sind. Da wird aus einem const T::iterator auch kein T::const_iterator .

    Ich will eigentlich nur, dass ich Rvalues in foo packen kann, und plötzlich kann ich den Pointee nicht mehr verändern:

    void foo(smart_pointer_mit_komischer_const_weiterleitung<T> const & p)//soll eigentlich nur mit Rvalues leben können
    {
        //*p modifizieren ->boing, weil's sich verhält, wie sich eigentlich smart_ptr<T const> verhalten sollte
    } 
    
    smart_pointer_mit_komischer_const_weiterleitung<T> some_class::get(){...}
    
    some_class x;
    
    foo(x.get()); //boing!
    

    Solls das wirklich sein?



  • Tachyon schrieb:

    Siehe übrigens auch Iteratoren, die ja auch eine Art Smartpointer sind. Da wird aus einem const T::iterator auch kein T::const_iterator .

    Ja und?


Anmelden zum Antworten