C++ Standardisierung: Ein erster Blick auf die Papers & C++14



  • Hallo C++ Community,

    habe eine Artikelserie angefangen, welche die verschiedenen Einreichungen zum nächsten C++ Committee Treffen in Bristol zusammenfasst:
    http://www.meetingcpp.com/index.php/br/items/a-look-at-cpp14-papers-part-1.html

    Dies sind die ersten 18 Papers, Teil 2 ist schon in Arbeit, plane jede Woche ein Update zu veröffentlichen.

    phlox81



  • DynArray! YEAH! 😃



  • Habe ich auch gedacht.



  • Aber du weißt schon, dass meine Begeisterung hauptsächlich daher kommt, da ich mich selbst daran versucht hab? Such mal "Dynarray Implementation"



  • Letztendlich sind das doch alles unwichtige Kleinigkeiten (ausser vlt optional, gibts aber eh schon in boost)...
    Wo bleibt der fix fuer std::allocator?



  • Kellerautomat schrieb:

    Letztendlich sind das doch alles unwichtige Kleinigkeiten (ausser vlt optional, gibts aber eh schon in boost)...
    Wo bleibt der fix fuer std::allocator?

    Polymorphic Allocators ist doch direkt das erste. Darin ist auch das man den Allocator vom Typen abkoppeln kann.
    Oder auf was genau beziehst du dich?



  • realloc done right



  • phlox81 schrieb:

    Polymorphic Allocators ist doch direkt das erste. Darin ist auch das man den Allocator vom Typen abkoppeln kann.

    Irgendwie sehe ich den Sinn dahinter nicht so recht, weshalb das in die Standardbibliothek soll.
    Eigene Allokatoren werden in der Praxis fast nie verwendet, ausser es geht wirklich um Speed und dann ist ein Template besser.

    Ausserdem steht im Standard nur ein Allokator zur Verfügung, um überhaupt von den polymorphen Allokatoren einen Nutzen zu ziehen, muss man entweder einen selbst schreiben (oft eine schlechte Idee) oder man verwendet eine externe Library. Und dann wäre es eine Aufgabe dieser externen Library, den polymorphen Allokator bereitzustellen. Wirklich schwierig ist das ja nicht selber zu schreiben.

    Die Hauptmotivation scheint Vorurteile gegen Templates zu sein (aus dem Proposal: "Templates lead to long compile times and bloated code"), aber da sucht man mit den Allokatoren völlig am falschen Ort 😕



  • polynom schrieb:

    phlox81 schrieb:

    Polymorphic Allocators ist doch direkt das erste. Darin ist auch das man den Allocator vom Typen abkoppeln kann.

    Irgendwie sehe ich den Sinn dahinter nicht so recht, weshalb das in die Standardbibliothek soll.
    Eigene Allokatoren werden in der Praxis fast nie verwendet, ausser es geht wirklich um Speed und dann ist ein Template besser.

    Ausserdem steht im Standard nur ein Allokator zur Verfügung, um überhaupt von den polymorphen Allokatoren einen Nutzen zu ziehen, muss man entweder einen selbst schreiben (oft eine schlechte Idee) oder man verwendet eine externe Library. Und dann wäre es eine Aufgabe dieser externen Library, den polymorphen Allokator bereitzustellen. Wirklich schwierig ist das ja nicht selber zu schreiben.

    Die Hauptmotivation scheint Vorurteile gegen Templates zu sein (aus dem Proposal: "Templates lead to long compile times and bloated code"), aber da sucht man mit den Allokatoren völlig am falschen Ort 😕

    Das mag für deine Domain stimmen, aber diesen Mechanismus in den Standard zu integrieren finde ich sehr gut.
    Allokatoren werden durchaus verwendet, das Proposal zeigt ja einen möglichen Anwendungsfall.



  • phlox81 schrieb:

    Das mag für deine Domain stimmen, aber diesen Mechanismus in den Standard zu integrieren finde ich sehr gut.
    Allokatoren werden durchaus verwendet, das Proposal zeigt ja einen möglichen Anwendungsfall.

    Den shared_alloc ? Ernsthaft, den Anwendungsfall finde ich sinnfrei.
    Ganz unnötig ist die Idee nicht, aber so etwas gehört z.B. in Boost und nicht in die Standardbibliothek, weil die Anzahl Nutzer dürfte sich in Grenzen halten, zumal es in der stdlib nur einen Allokator gibt.



  • Letztendlich sind das doch alles unwichtige Kleinigkeiten

    👍
    Aber einige davon sind schon doch witzig. Das mit den Literalen bspw. 😃



  • Gerade Allokatoren sind etwas, wo ich den Template-Ansatz einfach falsch finde. Allokatoren haben ein klares Interface, das nicht zum Typen gehoeren sollte.

    Ich schlage mal folgendes vor:

    struct memory_allocator
    {
        virtual void* allocate(std::size_t size) = 0;
        virtual bool reallocate(void* ptr, std::size_t new_size) = 0;
        virtual void free(void* ptr) = 0;
    
        virtual ~memory_allocator() {}
    
        // new, delete
        static memory_allocator& get_default();
        static void set_default(memory_allocator& alloc);
    };
    

    Einwaende?



  • Kellerautomat schrieb:

    Gerade Allokatoren sind etwas, wo ich den Template-Ansatz einfach falsch finde. Allokatoren haben ein klares Interface, das nicht zum Typen gehoeren sollte.

    Das sehe ich anders. Ein Container ist dafür zuständig, Elemente für den Anwendungszweck angepasst zu speichern und das hängt durchaus stark mit Allokatoren zusammen.

    Davon abgesehen entsteht dadurch ein gewisser Overhead, nämlich zusätzlicher Speicherverbrauch (mind. 1 Pointer pro Container) und zusätzliche Indirektionen.

    Das wirkliche Problem ist, den Inhalt zu abstrahieren, dafür sind (möglicherweise type-erased) Ranges da. Oder man leitet vector<int> von random_acces_range<int> ab. Aber nicht in dem man den Allokator erased.

    Abgesehen davon:

    virtual void* allocate(std::size_t size) = 0;
    

    Sollte mMn char* zurückgeben, aber das ist erstmal irrelevant.

    virtual bool reallocate(void* ptr, std::size_t new_size) = 0;
    

    Wie benutzt man das? Meintest du char*& ptr ?

    virtual void free(void* ptr) = 0;
    

    noexcept ...

    // new, delete
    static memory_allocator get_default();
    static void set_default(memory_allocator& alloc);
    

    Das sollte eher memory_allocator& get_default() mit [s|g]et_default_memory_factory() sein um Allokatoren mit Zuständen zu erlauben.

    Eine Überlegung wert wäre noch das Alignment mit einzubeziehen, weil das für small object allocators ganz nützlich sein könnte, also

    virtual char* allocate(std::size_t size, std::size_t alignment = /* default alignment */) = 0;
    virtual bool reallocate(char*& ptr, std::size_t new_size, std::size_t alignment = /* previously used alignment */) = 0;
    


  • Kellerautomat schrieb:

    realloc done right

    Hier muss man aufpassen, weil realloc in C++ nur Speicherblöcke vergrössert oder neue alloziert, und dabei weder Inhalte kopiert noch alte freigibt.



  • polynom schrieb:

    Eine Überlegung wert wäre noch das Alignment mit einzubeziehen, weil das für small object allocators ganz nützlich sein könnte

    Ausserdem ist es für SIMD notwendig.

    Deshalb sollte std::aligned_storage für *alle* Zweierpotenz-Alignments definiert sein und nicht nur für eine unbestimmte Anzahl.



  • polynom schrieb:

    Das sehe ich anders. Ein Container ist dafür zuständig, Elemente für den Anwendungszweck angepasst zu speichern und das hängt durchaus stark mit Allokatoren zusammen.

    Der Allokator ist lediglich dafuer verantwortlich, wo der speicher herkommt, das ist doch keine Eigenschaft des Containers. Warum sollte ein Container ueberhaupt einen Allokator besitzen (= als Member haben)? Das ergibt im momentanen Standard alles keinen Sinn.

    polynom schrieb:

    Davon abgesehen entsteht dadurch ein gewisser Overhead, nämlich zusätzlicher Speicherverbrauch (mind. 1 Pointer pro Container) und zusätzliche Indirektionen.

    Verstehe ich gerade nicht.

    polynom schrieb:

    Das wirkliche Problem ist, den Inhalt zu abstrahieren, dafür sind (möglicherweise type-erased) Ranges da. Oder man leitet vector<int> von random_acces_range<int> ab. Aber nicht in dem man den Allokator erased.

    Concepts, die wir hoffentlich in C++14 zumindest in einer Lite-Version auch noch bekommen.

    polynom schrieb:

    Abgesehen davon:

    virtual void* allocate(std::size_t size) = 0;
    

    Sollte mMn char* zurückgeben, aber das ist erstmal irrelevant.

    Sehe ich anders. void* heisst fuer mich einfach Zeiger auf "nichts bestimmtes" oder "irgendwas". Also roher Speicher.

    polynom schrieb:

    virtual bool reallocate(void* ptr, std::size_t new_size) = 0;
    

    Wie benutzt man das? Meintest du char*& ptr ?

    Nein. reallocate() versucht inplace zu reallozieren und gibt zurueck, ob das gelingt. Wenn nicht, muss der Benutzer selbst mit allocate() einen neuen Bereich allozieren. Dafuer kann er aber auch copy/move Ctoren aufrufen.

    polynom schrieb:

    virtual void free(void* ptr) = 0;
    

    noexcept ...

    Die Funktionen sind alle noexcept, hab daran gar nicht gedacht auf die Schnelle.

    polynom schrieb:

    // new, delete
    static memory_allocator get_default();
    static void set_default(memory_allocator& alloc);
    

    Das sollte eher memory_allocator& get_default() mit [s|g]et_default_memory_factory() sein um Allokatoren mit Zuständen zu erlauben.

    Niemand besitzt einen Allokator. Die werden per Referenz herumgereicht. Daher ist es auch egal, ob der Zustand hat, oder nicht.

    Edit: Achso, ja. Ich habe die Referenz hier vergessen.

    polynom schrieb:

    Eine Überlegung wert wäre noch das Alignment mit einzubeziehen, weil das für small object allocators ganz nützlich sein könnte, also

    virtual char* allocate(std::size_t size, std::size_t alignment = /* default alignment */) = 0;
    virtual bool reallocate(char*& ptr, std::size_t new_size, std::size_t alignment = /* previously used alignment */) = 0;
    

    Bei alignment bin ich mir unsicher. Waere aber wohl eine Ueberlegung wert. reallocate braeuchte aufgrund meiner obigen Definition allerdings keinen alignment-Parameter. Du dachtest hier bestimmt an ein C-realloc, das aber eben fuer C++ unbrauchbar ist.



  • Och, es gibt schon einige recht interessante Proposals: Polymorphic Lambdas, Resumable Functions, SIMD, Unicode, 🙂



  • Sone schrieb:

    Aber du weißt schon, dass meine Begeisterung hauptsächlich daher kommt, da ich mich selbst daran versucht hab? Such mal "Dynarray Implementation"

    Ich weiß, dass du das versucht hast.
    Zu dem Zeitpunkt habe ich mitgelesen und ab und zu nicht angemeldet geschrieben.
    Trotzdem habe ich einige Situationen, bei der ein vector zu viel ist.



  • Der einzige Zweck von dynarray ist dass es zb über alloca implementiert werden könnte. Ein vector für Arme ist wohl kaum eine sinnvolle Neuerung. 😉



  • Ethon schrieb:

    Der einzige Zweck von dynarray ist dass es zb über alloca implementiert werden könnte. Ein vector für Arme ist wohl kaum eine sinnvolle Neuerung. 😉

    Nö, ich finde nach wie vor, dass dynarray meinen Bedürfnissen entspricht. Manchmal brauche ich ein Array, das eben eine zur Laufzeit bekannte Größe hat, aber diese nicht verändern kann. Ich verstehe nicht, wieso ich da in vector einen Kompromiss sehen muss. Das ist kein Overbloat.


Anmelden zum Antworten