std::array C++11



  • Arcoth schrieb:

    Schau mal in die Header-Vorgabe. Da steht genau, wie std::array zu definieren ist. Das einzige Member-Objekt ist ein Array:

    T elems[N]; // exposition only [von §23.3.2.1/3]
    

    Genau das ist der Knackpunkt. Die wörtliche Übersetzung für exposition ist sowas wie Ausstellung. Ich würde das sinngemäß so übersetzen wie "Nur ums zu zeigen wie es gehen könnte". Sprich: das Array könnte auch sonst wie implementiert sein.

    Moment, mir fällt auch grad ein, der Standard kennt ja sowas wie Heap oder Stack gar nicht...


  • Mod

    Nein, nein. Der Kommentar heißt hier einfach, dass der Name des Arrays nur als Beispiel gegeben ist, und kein tatsächlicher Member von array ist.


  • Mod

    17.5.2.3 lesen und verstehen


  • Mod

    camper schrieb:

    17.5.2.3 lesen und verstehen

    Es kann praktisch nur ein echtes Array als Member geben. Der Standard fordert eine Initialisierungssyntax (s. §23.3.2.1/2), die nur ein Array als Member ermöglicht. Ein vector fällt durch, weil brace-elision nur für Aggregate funktioniert.

    Die einzige andere Möglichkeit besteht darin, das Subaggregat so zu definieren, dass es genauso viele Member hat wie das Template-Argument vorgibt. Das ist nur leider impraktikabel, da so nur eine maximale Größe von 4096 möglich wäre - siehe Anhang B.


  • Mod

    also mir fällt da so ein

    template <typename T, size_t N>
    struct array
    {
    ...
        T elems[1][1][1][1][1][N][1][1][1][1];
    };
    

    oder

    template <typename T, std::size_t N>
    struct array
    {
        array<T,(N+1)/2> x;
        array<T,N/2> y;
    };
    template <typename T>
    struct array<T,1>
    {
        T x;
    };
    template <typename T>
    struct array<T,0>
    {
    };
    

  • Mod

    😡 Eines Tages erwisch' ich dich, du mieser Hund!


  • Mod

    Warte! Letzteres ist gar nicht Standardkonform, weil...

    Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other

    Und

    The elements of an array are stored contiguously, meaning that if a is an array<T, N> then it obeys the identity &a[n] == &a[0] + n for all 0 <= n < N .



  • Skym0sh0 schrieb:

    Wäre es dann nicht angebracht, dass array selbst entscheidet, wann ein Array auf dem Stack oder dem Heap liegen soll?!

    Das wäre fein, sagen wir mal ab 65k geht's auf den Heap.

    Könnte gcc Compilererweiterungen einbasteln, und in der gcc-stdlib benutzen, damit das klappt und dem Standard nicht widerspricht?


  • Mod

    Könnte gcc Compilererweiterungen einbasteln, und in der gcc-stdlib benutzen, damit das klappt und dem Standard nicht widerspricht?

    Warum nicht einfach selber was basteln? Mit partieller Spezialisierung ist das ein Klacks. Muss doch nicht in den Standard, dynarray hats auch nicht geschafft.

    Und ich will mal sehen, wie man da um den Standard herum kommt, gerade wegen der Speicherkontinuitätsregel und der Initialisierungssyntax. Ich wette, jetzt gehen auch camper die Ideen aus.


  • Mod

    Hier, so ähnlich:

    #include <vector>
    #include <memory>
    
    template< typename T, std::size_t N, typename=void >
    struct Array
    {
    	T _elems[N]; // evt. mit Trick um zero-size-arrays zu erlauben
    
    	// ...
    };
    
    template< typename T, std::size_t N >
    struct Array<T, N, typename std::enable_if<N >= (1 << 16)>::type>
    {
    	std::unique_ptr<T[]> _elems{ new T[N] };
    
    	// ..
    };
    
    int main()
    {
    	Array<int, 70000> a;
    }
    

    So ist es sogar immer noch ein Aggregat.



  • Arcoth schrieb:

    Könnte gcc Compilererweiterungen einbasteln, und in der gcc-stdlib benutzen, damit das klappt und dem Standard nicht widerspricht?

    Warum nicht einfach selber was basteln? Mit partieller Spezialisierung ist das ein Klacks. Muss doch nicht in den Standard, dynarray hats auch nicht geschafft.

    Jo, was lokales dazu habe ich schon seit 10 Jahren, naja so ähnlich, den Vector<type,size,onHeap=(size>=8192)> oder so. Array brauche ich eher nie, weil irgendwie die Daten dann doch angekrochen oder gestreamt oder berechnet mit ungewisser Ergebnisanzahl oder so kommen.

    Wenn ich man drüber nachdenke, würde wohl auch >=64 fast reichen, denn wenn man die 64 Elemente tatsächlich anfassen will, kostet gegen die Berechnungen im Vector/Array das Allokieren/Deallokieren gar nicht mehr als einen Takt pro Element. Pah, 64-Bitter packen 8192 kompromisslos. Hast mich wieder zu nutzlosem Nachdenken gebracht, Du Schalk.


  • Mod

    Ich - bin - kein - Schalk! Du bist der Schalk!



  • Arcoth schrieb:

    Ich - bin - kein - Schalk! Du bist der Schalk!

    Wird noch, ich setze weiterhin große Hoffnungen in Dich.


  • Mod

    Arcoth schrieb:

    Warte! Letzteres ist gar nicht Standardkonform, weil...

    Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other

    genau: might
    Nirgendwo wird verlangt, dass die Implementation der Standardbibliothek portabel sein muss.

    Arcoth schrieb:

    template< typename T, std::size_t N >
    struct Array<T, N, typename std::enable_if<N >= (1 << 16)>::type>
    {
    	std::unique_ptr<T[]> _elems{ new T[N] };
    
    	// ..
    };
    

    So ist es sogar immer noch ein Aggregat.

    Ich glaube nicht. Initialisierer für nicht-statischen Member und so...


  • Mod

    Ich glaube nicht. Initialisierer für nicht-statischen Member und so...

    An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).


  • Mod

    Arcoth schrieb:

    Ich glaube nicht. Initialisierer für nicht-statischen Member und so...

    An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

    Quelle?


  • Mod

    N3797 natürlich. :p

    Übrigens:

    If a program contains no violations of the rules in this International Standard, a conforming implementation shall, within its resource limits, accept and correctly execute that program.

    Edit: Das Zitat ist völlig Sinnlos, weil - sobald die Standardbibliothek nicht mehr standardkonform ist - natürlich auch das Programm nicht standardkonform ist...


  • Mod

    Arcoth schrieb:

    N3797 natürlich. :p

    (Noch) kein Standard also. Das sollte nicht unterschlagen werden. Diese spezielle Änderung geht auf N3653 zurück.

    Für sinnvoll halte ich die Spezialisierung

    template< typename T, std::size_t N >
    struct Array<T, N, typename std::enable_if<N >= (1 << 16)>::type>
    {
        std::unique_ptr<T[]> _elems{ new T[N] };
    
        // ..
    };
    

    trotzdem nicht. Da die Aggregatinitialisierung nicht so funktioniert, wie sie soll, ist es unbedeutend, dass es in C++14 nun überhaupt ein Aggregat ist.

    Array<int, 100000> x = { 0, 1, 2 }; // geht nicht
    

    Der unique_ptr sollte sicher eher ein clone_ptr sein, sonst haben wir auch keine Kopiersemantik.
    std::array ist nur deshalb ein Aggregat, weil vor initializer_list und variadic templates eingeführt wurde. Eine modernisierte Variante würde statt dessen auf einen geeigneten Konstruktor setzen.

    Arcoth schrieb:

    Übrigens:

    If a program contains no violations of the rules in this International Standard, a conforming implementation shall, within its resource limits, accept and correctly execute that program.

    Edit: Das Zitat ist völlig Sinnlos, weil - sobald die Standardbibliothek nicht mehr standardkonform ist - natürlich auch das Programm nicht standardkonform ist...

    Das ist nur eine sinnlose Interpretation. Der Begriff "program" schließt hier die Implementation natürlich nicht mit ein.
    Und ob eine Implementation den Standard 100% richtig umsetzt oder nicht spielt keine Rolle in Hinblick auf die Konformität eines Programmes, dass diese nutzt.


  • Mod

    Noch) kein Standard also.

    Egal. Die Änderung wird bleiben, weil sie sinnvoll ist.

    Da die Aggregatinitialisierung nicht so funktioniert, wie sie soll, ist es unbedeutend, dass es in C++14 nun überhaupt ein Aggregat ist.

    Die Variante bekommt natürlich noch einen initializer-list-Konstruktor, und ist damit sowieso kein Aggregat mehr. Wollte es nur anmerken, weil ich genau die entfernte Regel gut fand.

    Der unique_ptr sollte sicher eher ein clone_ptr sein, sonst haben wir auch keine Kopiersemantik.

    Das gibt es im Standard gar nicht.

    Und ob eine Implementation den Standard 100% richtig umsetzt oder nicht spielt keine Rolle in Hinblick auf die Konformität eines Programmes, dass diese nutzt.

    Wenn ich ein Programm schreibe, dass (&arr[0])[5] benutzt, ist das natürlich UB.

    Du willst mir also weismachen, dass die Standardbibliothek auch einfach falsch implementiert werden kann, und das dem Standard völlig egal ist?


  • Mod

    Arcoth schrieb:

    Der unique_ptr sollte sicher eher ein clone_ptr sein, sonst haben wir auch keine Kopiersemantik.

    Das gibt es im Standard gar nicht.

    Dann wirst du einen bauen müssen.

    Arcoth schrieb:

    Du willst mir also weismachen, dass die Standardbibliothek auch einfach falsch implementiert werden kann, und das dem Standard völlig egal ist?

    Präzisier mal deine Frage. Dem Standard ist egal wie eine Sprachimplementation funktioniert. siehe auch 1.4/2


Anmelden zum Antworten